This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,26 @@
Test that section pforms are substituted with absolute paths.
$ . ./helpers.sh
$ make_lockdir
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (install (progn
> (run echo --prefix %{prefix})
> (run echo --prefix=%{prefix})))
> EOF
$ cat >dune-project <<EOF
> (lang dune 3.13)
> (package
> (name foo)
> (allow_empty)
> (depends test))
> EOF
Note that currently dune incorrectly substitutes relative paths for pforms that
appear in string interpolations.
$ build_pkg test 2>&1 | strip_sandbox
--prefix $SANDBOX/_private/default/.pkg/test/target
$SANDBOX/_private/default/.pkg/test/target

View file

@ -0,0 +1,57 @@
Test that we support the use case of using additional constraints to force the
system compiler to be used instead of installing the compiler.
$ . ./helpers.sh
Create packages resembling the ocaml compiler packages
$ mkrepo
$ mkpkg ocaml-base-compiler <<EOF
> conflicts: [ "ocaml-system" "ocaml-variants" ]
> EOF
$ mkpkg ocaml-variants <<EOF
> conflicts: [ "ocaml-system" "ocaml-base-compiler" ]
> EOF
$ mkpkg ocaml-system <<EOF
> conflicts: [ "ocaml-variants" "ocaml-base-compiler" ]
> EOF
$ mkpkg ocaml <<EOF
> depends: [
> "ocaml-base-compiler" | "ocaml-variants" | "ocaml-system"
> ]
> EOF
A package that depends on ocaml:
$ cat > dune-project <<EOF
> (lang dune 3.13)
> (package
> (name foo)
> (depends ocaml))
> EOF
Try solving without additional constraints:
$ add_mock_repo_if_needed
$ dune pkg lock
Solution for dune.lock:
- ocaml.0.0.1
- ocaml-base-compiler.0.0.1
Now make a workspace file adding the constarint on ocaml-system:
$ cat >dune-workspace <<EOF
> (lang dune 3.13)
> (lock_dir
> (constraints ocaml-system)
> (repositories mock))
> (repository
> (name mock)
> (url "file://$(pwd)/mock-opam-repository"))
> EOF
Solve again. This time ocaml-system is chosen.
$ dune pkg lock
Solution for dune.lock:
- ocaml.0.0.1
- ocaml-system.0.0.1

View file

@ -0,0 +1,75 @@
It's possible to include additional packages or constraints in workspace files:
$ . ./helpers.sh
$ cat >dune-workspace <<EOF
> (lang dune 3.11)
> (lock_dir
> (constraints doesnotexist foo (bar (= 1.0.0)))
> (repositories mock))
> (repository
> (name mock)
> (url "file://$(pwd)/mock-opam-repository"))
> EOF
$ mkrepo
$ mkpkg foo 1.0.0
$ mkpkg bar 1.0.0
$ mkpkg bar 1.9.1
Notice that the constraints field doesn't introduce additional packages. The
"doesnotexist" package isn't being pulled.
$ solve_project <<EOF
> (lang dune 3.11)
> (package
> (name x)
> (depends foo bar))
> EOF
Solution for dune.lock:
- bar.1.0.0
- foo.1.0.0
Constraint negation is supported since 3.18:
$ cat >dune-workspace <<EOF
> (lang dune 3.18)
> (lock_dir
> (constraints doesnotexist (foo (not (= 1.0.0))) (bar (not (= 1.0.0))))
> (repositories mock))
> (repository
> (name mock)
> (url "file://$(pwd)/mock-opam-repository"))
> EOF
There are no valid version of foo at the moment:
$ solve_project <<EOF
> (lang dune 3.18)
> (package
> (name x)
> (depends foo bar))
> EOF
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
Selected candidates: bar.1.9.1 x.dev
- foo -> (problem)
No usable implementations:
foo.1.0.0: Package does not satisfy constraints of local package x
[1]
If we add one:
$ mkpkg foo 0.9.0
$ solve_project <<EOF
> (lang dune 3.18)
> (package
> (name x)
> (depends foo bar))
> EOF
Solution for dune.lock:
- bar.1.9.1
- foo.0.9.0

View file

@ -0,0 +1,56 @@
This test verifies the @pkg-install alias fetch and build the project dependencies
without building the project itself.
$ . ./helpers.sh
Create a project using the fake library as a dependency:
$ cat > dune-project << EOF
> (lang dune 3.16)
> (package
> (name bar)
> (allow_empty)
> (depends foo))
> EOF
Ensure the alias is not available outside of the package manamgent context:
$ dune build @pkg-install
Error: The @pkg-install alias cannot be used without a lock dir
-> required by alias pkg-install
Hint: You might want to create the lock dir with 'dune pkg lock'
[1]
Create a fake package which echoes information to stdout when build:
$ make_lockdir
$ cat > dune.lock/foo.pkg << EOF
> (version 0.0.1)
> (build
> (run echo "Build package foo"))
> (install
> (run echo "Install package foo"))
> EOF
Create a rule to show that this rule is not called with `@pkg-install` as `bar`
is not build when calling the alias. If called, it would output the content of
the `bar.ml` file:
$ cat > dune << EOF
> (executable
> (name bar))
> (rule
> (target bar.ml)
> (action
> (progn
> (with-stdout-to %{target} (echo "let _ = 42"))
> (system "cat %{target}"))))
> EOF
The alias call builds the `foo` dependency but not the project itself. It
displays the output of the fake package but not of the `bar.exe` executable:
$ dune build @pkg-install
Build package foo
Install package foo
If we build the executable, it only shows the content of the executable as dune
already built the `foo` dependency when calling `@pkg-install`:
$ dune build ./bar.exe
let _ = 42

View file

@ -0,0 +1,77 @@
Test that dune can handle the case where a dependency's source contains a
symlink with a missing destination.
$ . ./helpers.sh
Define a package foo containing a broken symlink.
$ mkdir foo
$ touch foo/a.txt
$ ln -s non_existent foo/b.txt
Define a package bar containing a broken symlink.
$ mkdir bar
$ touch bar/a.txt
$ ln -s non_existent bar/b.txt
$ tar czf bar.tar.gz bar
Make a directory to contain a test project and change to it.
$ mkdir project
$ cd project
Create a lockdir for the project.
$ mkdir dune.lock
$ cat > dune.lock/lock.dune <<EOF
> (lang package 0.1)
> EOF
The package "foo" exercises copying package sources from a local directory.
$ cat > dune.lock/foo.pkg <<EOF
> (version 0.0.1)
> (source
> (fetch
> (url
> file:///$PWD/../foo)))
> EOF
The package "bar" exercises extracting a source archive from a local file.
$ cat > dune.lock/bar.pkg <<EOF
> (version 0.0.1)
> (source
> (fetch
> (url
> file:///$PWD/../bar.tar.gz)))
> EOF
The package "bar" exercises extracting a source archive from a downloaded file.
$ cat > dune.lock/baz.pkg <<EOF
> (version 0.0.1)
> (source
> (fetch
> (url http://0.0.0.0:1)
> (checksum md5=$(md5sum $PWD/../bar.tar.gz | cut -f1 -d' '))))
> EOF
Set up a fake web server to serve the source archive for the package "bar".
$ echo $PWD/../bar.tar.gz >> fake-curls
Make a project file that depends on all the packages.
$ cat > dune-project <<EOF
> (lang dune 3.17)
> (package
> (name x)
> (allow_empty)
> (depends foo bar baz))
> EOF
Build the packages.
$ build_pkg foo
$ build_pkg bar
$ build_pkg baz
All files were copied except for the broken symlinks:
$ ls _build/_private/default/.pkg/foo/source
a.txt
$ ls _build/_private/default/.pkg/bar/source
a.txt
$ ls _build/_private/default/.pkg/baz/source
a.txt

View file

@ -0,0 +1,48 @@
Test the error message when installing package that fails.
$ . ./helpers.sh
$ make_lockdir
$ export DUNE_DEBUG_PACKAGE_LOGS=0
Make a project with two packages, one successful and one that fails:
$ cat > dune-project << EOF
> (lang dune 3.12)
> EOF
Create a package with a failing command that throws an error:
$ make_lockpkg x << EOF
> (version 0.0.1)
> (build
> (progn
> (run cat i_dont_exist)))
> EOF
Building the package should fail and print an error:
$ build_pkg x 2>&1 | sed -E 's#/.*/cat#cat#g'
File "dune.lock/x.pkg", line 4, characters 11-14:
4 | (run cat i_dont_exist)))
^^^
Error: Logs for package x
cat: i_dont_exist: No such file or directory
Create a package with a succeeding command that displays some text:
$ make_lockpkg y << EOF
> (version 0.0.1)
> (build
> (progn
> (run echo "Success!")))
> EOF
Building the package should succeed and print no output:
$ build_pkg y
Checks the package is installed:
$ show_pkg_cookie y
{ files = map {}; variables = [] }

View file

@ -0,0 +1,31 @@
Requesting to build a single package should not build unrelated things:
$ . ./helpers.sh
$ make_lockdir
$ cat >dune-project <<EOF
> (lang dune 3.12)
> EOF
$ pkg() {
> make_lockpkg $1 <<EOF
> (build (run echo building $1))
> (version dev)
> EOF
> }
These two packages are independent:
$ pkg foo
$ pkg bar
We should only see the result of building "foo"
$ build_pkg foo
building foo
We should only see the result of building "bar"
$ build_pkg bar
building bar

View file

@ -0,0 +1,141 @@
Tests that changing the dependencies of a project cause lockdir validation to
fail due to the dependency hash not matching the hash stored in the lockdir.
Dummy opam repo so we can generate lockdirs
$ . ./helpers.sh
$ mkrepo
$ mkpkg a <<EOF
> EOF
Start with a project with a single package with no dependencies:
$ solve_project <<EOF
> (lang dune 3.11)
> (package
> (name foo))
> EOF
Solution for dune.lock:
(no dependencies to lock)
$ cat dune.lock/lock.dune
(lang package 0.1)
(repositories
(complete false)
(used))
$ dune pkg validate-lockdir
Add a dependency to the project:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package
> (name foo)
> (depends a))
> EOF
$ dune pkg validate-lockdir
Lockdir dune.lock does not contain a solution for local packages:
Error: This project has at least one non-local dependency but the lockdir
doesn't contain a dependency hash.
An example of a non-local dependency of this project is: a
Hint: Regenerate the lockdir by running 'dune pkg lock'
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Add a non-local dependency to the package:
$ solve_project <<EOF
> (lang dune 3.11)
> (package
> (name foo)
> (depends a))
> EOF
Solution for dune.lock:
- a.0.0.1
$ cat dune.lock/lock.dune
(lang package 0.1)
(dependency_hash 7ba1cacd46bb2609d7b9735909c3b8a5)
(repositories
(complete false)
(used))
$ dune pkg validate-lockdir
Add a second dependency to the project:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package
> (name foo)
> (depends a b))
> EOF
$ dune pkg validate-lockdir
Lockdir dune.lock does not contain a solution for local packages:
File "dune.lock/lock.dune", line 3, characters 17-49:
Error: Dependency hash in lockdir does not match the hash of non-local
dependencies of this project. The lockdir expects the the non-local
dependencies to hash to:
7ba1cacd46bb2609d7b9735909c3b8a5
...but the non-local dependencies of this project hash to:
d18946fdd9833ae312d309f654f11c1b
Hint: Regenerate the lockdir by running 'dune pkg lock'
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Remove all dependencies from the project:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package
> (name foo))
> EOF
$ dune pkg validate-lockdir
Lockdir dune.lock does not contain a solution for local packages:
File "dune.lock/lock.dune", line 3, characters 17-49:
Error: This project has no non-local dependencies yet the lockfile contains a
dependency hash: 7ba1cacd46bb2609d7b9735909c3b8a5
Hint: Regenerate the lockdir by running 'dune pkg lock'
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Exercise handling invalid dependency hashes.
$ make_lock_metadata_with_hash() {
> cat >dune.lock/lock.dune <<EOF
> (lang package 0.1)
> (dependency_hash $1)
> (repositories
> (complete false)
> (used))
> EOF
> }
Case where the label ("md5") is missing:
$ make_lock_metadata_with_hash badhash
$ dune pkg validate-lockdir
Failed to parse lockdir dune.lock:
File "dune.lock/lock.dune", line 2, characters 17-24:
Error: Dependency hash is not a valid md5 hash: badhash
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Case where the label is not "md5":
$ make_lock_metadata_with_hash foo=badhash
$ dune pkg validate-lockdir
Failed to parse lockdir dune.lock:
File "dune.lock/lock.dune", line 2, characters 17-28:
Error: Dependency hash is not a valid md5 hash: foo=badhash
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Case where the the hash is not a valid md5 hash:
$ make_lock_metadata_with_hash md5=badhash
$ dune pkg validate-lockdir
Failed to parse lockdir dune.lock:
File "dune.lock/lock.dune", line 2, characters 17-28:
Error: Dependency hash is not a valid md5 hash: md5=badhash
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]

View file

@ -0,0 +1,23 @@
Make sure that we verify archives of local archives
$ . ./helpers.sh
$ make_lockdir
$ touch foo.tar.gz
$ make_lockpkg foo <<EOF
> (version 0.0.1)
> (source
> (fetch
> (checksum md5=069aa55d40e548280f92af693f6c625a)
> (url $PWD/foo.tar.gz)))
> EOF
$ build_pkg foo
File "dune.lock/foo.pkg", line 4, characters 12-48:
4 | (checksum md5=069aa55d40e548280f92af693f6c625a)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: Invalid checksum, got
md5=d41d8cd98f00b204e9800998ecf8427e
[1]

View file

@ -0,0 +1,23 @@
Make sure we can run exes from the user's PATH variable.
$ . ./helpers.sh
Create a directory containing a shell script and add the directory to PATH.
$ mkdir bin
$ cat > bin/hello <<EOF
> #!/bin/sh
> echo "Hello, World!"
> EOF
$ chmod a+x bin/hello
$ export PATH=$PATH:$PWD/bin
Create a lockdir with a lockfile that runs the shell script in a build command.
$ make_lockdir
$ cat >dune.lock/test.pkg <<'EOF'
> (version 0.0.1)
> (build (run hello))
> EOF
The build command is run from an environment including the custom PATH variable.
$ build_pkg test
Hello, World!

View file

@ -0,0 +1,36 @@
What happens if a branch has the same format as a ref?
$ . ../git-helpers.sh
$ . ./helpers.sh
$ mkrepo
$ mkpkg foo 1.0
$ cd mock-opam-repository
$ git init --quiet
$ git add -A
$ git commit --quiet -m "Initial state, foo.1.0"
$ AMBIGUOUS_REF=c3ba68d69316351bc660679f68fdc871bfb4f2d2
$ git switch --quiet -c $AMBIGUOUS_REF
$ mkpkg foo 2.0
$ git add -A
$ git commit --quiet -m "New foo.2.0 on branch $AMBIGUOUS_REF"
$ git switch --quiet -
$ cd ..
Use this ref in a project
$ add_mock_repo_if_needed "git+file://$PWD/mock-opam-repository#$AMBIGUOUS_REF"
Depend on foo from the repo
$ cat > dune-project <<EOF
> (lang dune 3.10)
>
> (package
> (name bar)
> (depends foo))
> EOF
Which foo will we get?
$ dune pkg lock 2>&1 | head -1 | sed "s/$AMBIGUOUS_REF/\$AMBIGUOUS_REF/g"
revision "$AMBIGUOUS_REF" not found in

View file

@ -0,0 +1,28 @@
Demonstrate that local dependencies that are marked as {with-test} can be
included.
$ . ./helpers.sh
$ mkrepo
$ mkpkg post <<EOF
> EOF
$ mkpkg build <<EOF
> EOF
$ mkpkg dev <<EOF
> EOF
$ mkpkg test <<EOF
> EOF
$ mkpkg doc <<EOF
> EOF
$ mkpkg dev-setup <<EOF
> EOF
Note that dune solves packages with with-doc and with-dev-setup always set to false, so
documentation-only deps are omitted from the solution.
Dune will also not include dependencies marked `post` in the lock directory.
$ solve "(test :with-test) (doc :with-doc) (dev-setup :with-dev-setup) (dev :with-dev) (build :build) (post :post)"
Solution for dune.lock:
- build.0.0.1
- test.0.0.1

View file

@ -0,0 +1,52 @@
Exercise dune resolving the post dependencies found in compiler packages.
$ . ./helpers.sh
$ mkrepo
$ cat >dune-workspace << EOF
> (lang dune 3.16)
> (lock_dir
> (path dune.lock)
> (repositories mock)
> (solver_env
> (os linux)))
> EOF
$ mkpkg host-system-other
$ mkpkg system-mingw << EOF
> available: os = "win32"
> EOF
$ mkpkg ocaml << EOF
> depends: [
> "ocaml-base-compiler"
> ]
> EOF
This package has a dependency cycle with the "ocaml" package, broken
by the use of post dependencies. It also contains a formula with no
solutions when the "post" variable is set to "false" on non-windows
systems. Opam evaluates dependency formulae with post=true and then
does further filtering to remove post dependencies from dependency
lists to prevent circular dependencies at package build time.
$ mkpkg ocaml-base-compiler << EOF
> depends: [
> "ocaml" {post}
> (("arch-x86_64" {os = "win32" & arch = "x86_64"} & "system-mingw" &
> "mingw-w64-shims" {os-distribution = "cygwin" & build}) |
> ("arch-x86_32" {os = "win32"} & "ocaml-option-bytecode-only" &
> "system-mingw" &
> "mingw-w64-shims" {os-distribution = "cygwin" & build}) |
> "host-system-other" {os != "win32" & post})
> ]
> EOF
$ solve ocaml-base-compiler
Solution for dune.lock:
- ocaml-base-compiler.0.0.1
Ensure that packages can be resolved at build time. This checks that
the dependency cycle between the "ocaml" and "ocaml-base-compiler"
packages is successfully broken by the use of post dependencies.
$ dune build

View file

@ -0,0 +1,130 @@
Test that dune will add checksums to lockfiles when the package has a source
archive but no checksum. This test uses an http server to serve packages to
test checksum generation, since we only generate checksums for packages
downloaded from non-local sources.
$ . ./helpers.sh
$ mkrepo
A file that will comprise the package source:
$ echo "Hello, World!" > foo.txt
$ echo foo.txt > fake-curls
$ PORT=1
$ mkpkg foo <<EOF
> url {
> src: "http://0.0.0.0:$PORT"
> }
> EOF
$ solve foo
Package "foo" has source archive which lacks a checksum.
The source archive will be downloaded from: http://0.0.0.0:1
Dune will compute its own checksum for this source archive.
Solution for dune.lock:
- foo.0.0.1
Replace the path in the lockfile as it would otherwise include the sandbox
path.
$ cat dune.lock/foo.pkg
(version 0.0.1)
(source
(fetch
(url http://0.0.0.0:1)
(checksum md5=bea8252ff4e80f41719ea13cdf007273)))
(dev)
Now make sure we can gracefully handle the case when the archive is missing.
Recreate the foo package with a fake port number to signal that the file will
404:
$ PORT=9000
$ mkpkg foo <<EOF
> url {
> src: "http://0.0.0.0:$PORT"
> }
> EOF
$ solve foo 2>&1
Package "foo" has source archive which lacks a checksum.
The source archive will be downloaded from: http://0.0.0.0:9000
Dune will compute its own checksum for this source archive.
Warning: download failed with code 404
Solution for dune.lock:
- foo.0.0.1
$ cat dune.lock/foo.pkg
(version 0.0.1)
(source
(fetch
(url http://0.0.0.0:9000)))
(dev)
Check that no checksum is computed for a local source file:
$ mkpkg foo <<EOF
> url {
> src: "$PWD/foo.txt"
> }
> EOF
$ solve foo 2>&1
Solution for dune.lock:
- foo.0.0.1
Check that no checksum is computed for a local source directory:
$ mkdir src
$ mkpkg foo <<EOF
> url {
> src: "$PWD/src"
> }
> EOF
$ solve foo 2>&1
Solution for dune.lock:
- foo.0.0.1
Create 3 packages that all share the same source url with no checksum. Dune
will need to download each package's source archive to compute their hashes.
Test that dune only downloads the file a single time since the source url is
identical among the packages. The fact that the download only occurs once is
asserted by the fact that the webserver will only serve the file a single time.
$ echo foo.txt >> fake-curls
$ PORT=2
$ mkpkg foo <<EOF
> url {
> src: "http://0.0.0.0:$PORT"
> }
> EOF
$ mkpkg bar <<EOF
> url {
> src: "http://0.0.0.0:$PORT"
> }
> EOF
$ mkpkg baz <<EOF
> url {
> src: "http://0.0.0.0:$PORT"
> }
> EOF
$ solve foo bar baz
Package "bar" has source archive which lacks a checksum.
The source archive will be downloaded from: http://0.0.0.0:2
Dune will compute its own checksum for this source archive.
Package "baz" has source archive which lacks a checksum.
The source archive will be downloaded from: http://0.0.0.0:2
Dune will compute its own checksum for this source archive.
Package "foo" has source archive which lacks a checksum.
The source archive will be downloaded from: http://0.0.0.0:2
Dune will compute its own checksum for this source archive.
Solution for dune.lock:
- bar.0.0.1
- baz.0.0.1
- foo.0.0.1

View file

@ -0,0 +1,59 @@
This test demonstrates a local package that's in the same conflict-class of a
dependency.
$ . ./helpers.sh
$ mkrepo
$ add_mock_repo_if_needed
$ mkpkg conflict-class
$ mkpkg bar <<EOF
> conflict-class: "ccc"
> EOF
Local conflict class defined in a local package:
$ cat >foo.opam <<EOF
> opam-version: "2.0"
> depends: [ "bar" ]
> conflict-class: "ccc"
> EOF
$ cat >x.opam <<EOF
> opam-version: "2.0"
> depends: "foo"
> EOF
$ cat >dune-project <<EOF
> (lang dune 3.11)
> EOF
$ dune pkg lock
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
Selected candidates: foo.dev x.dev foo&x
- bar -> (problem)
Rejected candidates:
bar.0.0.1: In same conflict class (ccc) as foo
[1]
Now the conflict class comes from the opam repository
$ mkpkg foo <<EOF
> depends: [ "bar" ]
> conflict-class: "ccc"
> EOF
$ rm foo.opam
$ dune pkg lock
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
Selected candidates: foo.0.0.1 x.dev
- bar -> (problem)
Rejected candidates:
bar.0.0.1: In same conflict class (ccc) as foo
[1]

View file

@ -0,0 +1,127 @@
The solver should repsect the (conflicts) field of the (package) stanza.
$ . ./helpers.sh
$ mkrepo
$ mkpkg foo 0.0.1
$ mkpkg bar << EOF
> depends: [ "foo" ]
> EOF
The solver should say no solution rather than just ignoring the conflict.
$ solve_project << EOF
> (lang dune 3.11)
> (package
> (name x)
> (allow_empty)
> (conflicts foo)
> (depends bar))
> EOF
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
Selected candidates: bar.0.0.1 x.dev
- foo -> (problem)
No usable implementations:
foo.0.0.1: Package does not satisfy constraints of local package x
[1]
There could be more than one conflict and they can have version constraints:
$ mkpkg foo2 0.0.1
$ mkpkg bar2 << EOF
> depends: [ "foo2" ]
> EOF
$ solve_project << EOF
> (lang dune 3.11)
> (generate_opam_files true)
> (package
> (name x)
> (allow_empty)
> (conflicts (foo (< 0.2)) (foo2 (< 0.2)))
> (depends bar bar2))
> EOF
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
Selected candidates: bar.0.0.1 bar2.0.0.1 x.dev
- foo -> (problem)
No usable implementations:
foo.0.0.1: Package does not satisfy constraints of local package x
- foo2 -> (problem)
No usable implementations:
foo2.0.0.1: Package does not satisfy constraints of local package x
[1]
When conflicts are obtained from an opam file instead of a dune-project,
the behaviour should be the same:
$ dune build x.opam
$ sed -n '/conflicts/,/]/p' x.opam
conflicts: [
"foo" {< "0.2"}
"foo2" {< "0.2"}
]
Even though the conflicts are listed by opam without a `|` to indicate a
disjunction, either package is problematic:
$ mkpkg dune 3.11
$ echo '(lang dune 3.11)' | solve_project 2>&1 | sed -E 's/3.[0-9]+/3.XX/'
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
Selected candidates: bar.0.0.1 bar2.0.0.1 x.dev
- dune -> dune.3.XX
User requested = 3.XX
- foo -> (problem)
No usable implementations:
foo.0.0.1: Package does not satisfy constraints of local package x
- foo2 -> (problem)
No usable implementations:
foo2.0.0.1: Package does not satisfy constraints of local package x
Adding a new version of `foo` only resolves one conflict:
$ mkpkg foo 0.2
$ echo '(lang dune 3.11)' | solve_project 2>&1 | sed -E 's/3.[0-9]+/3.XX/'
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
Selected candidates: bar.0.0.1 bar2.0.0.1 foo.0.2 x.dev
- dune -> dune.3.XX
User requested = 3.XX
- foo2 -> (problem)
No usable implementations:
foo2.0.0.1: Package does not satisfy constraints of local package x
Addition of `foo2` to solve the last remaining conflict:
$ mkpkg foo2 0.2
$ solve_project <<EOF
> (lang dune 3.11)
> EOF
Solution for dune.lock:
- bar.0.0.1
- bar2.0.0.1
- foo.0.2
- foo2.0.2
Same but checking that the latest versions of `foo` and `foo2` are not selected
due to the version constraints conflicts:
$ solve_project << EOF
> (lang dune 3.11)
> (generate_opam_files true)
> (package
> (name x)
> (allow_empty)
> (conflicts (foo (>= 0.2)) (foo2 (>= 0.2)))
> (depends bar bar2))
> EOF
Solution for dune.lock:
- bar.0.0.1
- bar2.0.0.1
- foo.0.0.1
- foo2.0.0.1

View file

@ -0,0 +1,23 @@
Exercise the solver on a package with a conjunction in its dependency
constraints.
$ . ./helpers.sh
$ mkrepo
$ mkpkg a
$ mkpkg foo << EOF
> depends: [
> "a" { >= "0.0.0" & < "1.0.0" }
> ]
> EOF
$ solve foo
Solution for dune.lock:
- a.0.0.1
- foo.0.0.1
$ cat dune.lock/foo.pkg
(version 0.0.1)
(depends a)

View file

@ -0,0 +1,370 @@
$ . ./helpers.sh
$ mkrepo
$ mkpkg standard-dune <<EOF
> build: [
> ["dune" "subst"] {dev}
> [
> "dune"
> "build"
> "-p"
> name
> "-j"
> jobs
> "@install"
> "@runtest" {with-test}
> "@doc" {with-doc}
> ]
> ]
> install: [ make "install" ]
> EOF
$ mkpkg with-interpolation <<EOF
> build: [
> [
> "./configure"
> "--prefix=%{prefix}%"
> "--docdir=%{doc}%/ocaml"
> ]
> [make "-j%{jobs}%"]
> ]
> install: [make "install"]
> EOF
Make sure we don't mess up percent signs that aren't part of variable interpolation syntax:
$ mkpkg with-percent-sign <<EOF
> build: [ "printf" "%d" "42" ]
> EOF
$ mkpkg with-malformed-interpolation <<EOF
> build: [ "./configure" "--prefix=%{prefix" ]
> EOF
$ mkpkg variable-types <<EOF
> build: [
> ["echo" local_var]
> ["echo" _:explicit_local_var]
> ["echo" foo:package_var]
> ["echo" os-family]
> ]
> EOF
Package for exercising opam filters on commands:
$ mkpkg exercise-filters <<EOF
> build: [
> [ "echo" "a" ] { foo }
> [ "echo" "b" ] { foo & bar }
> [ "echo" "c" ] { foo & bar & baz }
> [ "echo" "d" ] { foo | bar }
> [ "echo" "e" ] { foo | bar & baz }
> [ "echo" "f" ] { (foo | bar) & baz }
> [ "echo" "b" ] { foo = bar }
> [ "echo" "g" ] { version < "1.0" }
> [ "echo" "h" ] { with-test & ocaml:version < "5.0.0" }
> [ "echo" "i" ] { true }
> [ "echo" "j" ] { ! false }
> [ "echo" "k" ] { foo:installed }
> [ "echo" "l" ] { foo:version < "0.4" }
> [ "echo" "m" ] { foo+bar+baz:installed }
> [ "echo" "n" ] { ? madeup }
> [ "echo" "o" ] { ? installed }
> ]
> EOF
Package for exercising opam filters on terms:
$ mkpkg exercise-term-filters <<EOF
> build: [
> [ "echo" "a" "b" { foo } "c" { bar & baz } ]
> ]
> EOF
Package which has boolean where string was expected. This should be caught while parsing:
$ mkpkg filter-error-bool-where-string-expected <<EOF
> build: [
> [ "echo" "a" ] { foo:version < (foo = bar) }
> ]
> EOF
$ solve standard-dune with-interpolation with-percent-sign variable-types
Solution for dune.lock:
- standard-dune.0.0.1
- variable-types.0.0.1
- with-interpolation.0.0.1
- with-percent-sign.0.0.1
$ cat dune.lock/standard-dune.pkg
(version 0.0.1)
(install
(run %{make} install))
(build
(progn
(when
%{pkg-self:dev}
(run dune subst))
(run dune build -p %{pkg-self:name} -j %{jobs} @install)))
$ cat dune.lock/with-interpolation.pkg
(version 0.0.1)
(install
(run %{make} install))
(build
(progn
(run ./configure --prefix=%{prefix} --docdir=%{doc}/ocaml)
(run %{make} -j%{jobs})))
$ cat dune.lock/with-percent-sign.pkg
(version 0.0.1)
(build
(run printf %d 42))
$ cat dune.lock/variable-types.pkg
(version 0.0.1)
(build
(progn
(run echo %{pkg-self:local_var})
(run echo %{pkg-self:explicit_local_var})
(run echo %{pkg:foo:package_var})
(run echo %{os_family})))
$ solve with-malformed-interpolation
File "$TESTCASE_ROOT/mock-opam-repository/packages/with-malformed-interpolation/with-malformed-interpolation.0.0.1/opam", line 1, characters 0-0:
Error: Encountered malformed variable interpolation while processing commands
for package with-malformed-interpolation.0.0.1.
The variable interpolation:
%{prefix
[1]
$ solve exercise-filters
Solution for dune.lock:
- exercise-filters.0.0.1
$ cat dune.lock/exercise-filters.pkg
(version 0.0.1)
(build
(progn
(when
%{pkg-self:foo}
(run echo a))
(when
(and_absorb_undefined_var %{pkg-self:foo} %{pkg-self:bar})
(run echo b))
(when
(and_absorb_undefined_var %{pkg-self:foo} %{pkg-self:bar} %{pkg-self:baz})
(run echo c))
(when
(or_absorb_undefined_var %{pkg-self:foo} %{pkg-self:bar})
(run echo d))
(when
(or_absorb_undefined_var
%{pkg-self:foo}
(and_absorb_undefined_var %{pkg-self:bar} %{pkg-self:baz}))
(run echo e))
(when
(and_absorb_undefined_var
(or_absorb_undefined_var %{pkg-self:foo} %{pkg-self:bar})
%{pkg-self:baz})
(run echo f))
(when
(= %{pkg-self:foo} %{pkg-self:bar})
(run echo b))
(when
(< %{pkg-self:version} 1.0)
(run echo g))
(run echo i)
(run echo j)
(when
%{pkg:foo:installed}
(run echo k))
(when
(< %{pkg:foo:version} 0.4)
(run echo l))
(when
(and %{pkg:foo:installed} %{pkg:bar:installed} %{pkg:baz:installed})
(run echo m))))
Test that if opam filter translation is disabled the output doesn't contain any translated filters:
$ solve exercise-filters
Solution for dune.lock:
- exercise-filters.0.0.1
$ cat dune.lock/exercise-filters.pkg
(version 0.0.1)
(build
(progn
(when
%{pkg-self:foo}
(run echo a))
(when
(and_absorb_undefined_var %{pkg-self:foo} %{pkg-self:bar})
(run echo b))
(when
(and_absorb_undefined_var %{pkg-self:foo} %{pkg-self:bar} %{pkg-self:baz})
(run echo c))
(when
(or_absorb_undefined_var %{pkg-self:foo} %{pkg-self:bar})
(run echo d))
(when
(or_absorb_undefined_var
%{pkg-self:foo}
(and_absorb_undefined_var %{pkg-self:bar} %{pkg-self:baz}))
(run echo e))
(when
(and_absorb_undefined_var
(or_absorb_undefined_var %{pkg-self:foo} %{pkg-self:bar})
%{pkg-self:baz})
(run echo f))
(when
(= %{pkg-self:foo} %{pkg-self:bar})
(run echo b))
(when
(< %{pkg-self:version} 1.0)
(run echo g))
(run echo i)
(run echo j)
(when
%{pkg:foo:installed}
(run echo k))
(when
(< %{pkg:foo:version} 0.4)
(run echo l))
(when
(and %{pkg:foo:installed} %{pkg:bar:installed} %{pkg:baz:installed})
(run echo m))))
$ solve exercise-term-filters
Solution for dune.lock:
- exercise-term-filters.0.0.1
$ cat dune.lock/exercise-term-filters.pkg
(version 0.0.1)
(build
(run
echo
a
(when
(catch_undefined_var %{pkg-self:foo} false)
b)
(when
(catch_undefined_var
(and_absorb_undefined_var %{pkg-self:bar} %{pkg-self:baz})
false)
c)))
$ solve filter-error-bool-where-string-expected
File "$TESTCASE_ROOT/mock-opam-repository/packages/filter-error-bool-where-string-expected/filter-error-bool-where-string-expected.0.0.1/opam", line 3, characters 33-34:
3 | [ "echo" "a" ] { foo:version < (foo = bar) }
^
Error: unable to parse opam file
Parse error
[1]
Package with package conjunction and string selections inside variable interpolations:
$ mkpkg package-conjunction-and-string-selection <<EOF
> build: [
> [ "echo" "a %{installed}% b" ]
> [ "echo" "c %{installed?x:y}% d" ]
> [ "echo" "e %{foo:installed?x:y}% f" ]
> [ "echo" "g %{foo+bar+_:installed?x:y}% h" ]
> # The "enable" variable is syntactic sugar around "installed" in some (but not all) cases.
> # Its intention appears to be for use with ./configure scripts that take --enable-<feature> or
> # --disable-<feature> as arguments.
> [ "echo" "--%{enable}%-feature" ]
> [ "echo" "--%{_:enable}%-feature" ]
> [ "echo" "--%{foo+bar:enable}%-feature" ]
> [ "echo" "--%{foo+bar:enable?x:y}%-feature" ]
> ]
> EOF
$ solve_project <<EOF
> (lang dune 3.8)
> (package (name x) (depends package-conjunction-and-string-selection))
> EOF
Solution for dune.lock:
- package-conjunction-and-string-selection.0.0.1
Note that "enable" is not a true opam variable. Opam desugars occurrences of
"pkg:enable" into "pkg:enable?enable:disable" but if the explicit package scope
is omitted then it's treated like a regular variable. That explains why the
opam syntax `"--%{enable}%-feature"` is converted to
`--%{pkg-self:enable}-feature`. Also if the "enable" pseudo-variable is used
with an explicit string conversion it is treated as a regular variable which
explains why the opam syntax `"--%{foo+bar:enable?x:y}%-feature"` is converted
to a dune if-statement that checks the "enable" variable (rather than the
"installed" variable as in other cases).
It's probably an error for opam packages to use the "enable" in ways that opam
doesn't desugar but these tests are included so we can check that behaviour is
preserved between opam and dune.
$ cat dune.lock/package-conjunction-and-string-selection.pkg
(version 0.0.1)
(build
(progn
(run echo "a %{pkg-self:installed} b")
(run
echo
(concat
"c "
(if
(catch_undefined_var %{pkg-self:installed} false)
x
y)
" d"))
(run
echo
(concat
"e "
(if
(catch_undefined_var %{pkg:foo:installed} false)
x
y)
" f"))
(run
echo
(concat
"g "
(if
(catch_undefined_var
(and %{pkg:foo:installed} %{pkg:bar:installed} %{pkg-self:installed})
false)
x
y)
" h"))
(run echo --%{pkg-self:enable}-feature)
(run
echo
(concat
--
(if
(catch_undefined_var %{pkg-self:installed} false)
enable
disable)
-feature))
(run
echo
(concat
--
(if
(catch_undefined_var
(and %{pkg:foo:installed} %{pkg:bar:installed})
false)
enable
disable)
-feature))
(run
echo
(concat
--
(if
(catch_undefined_var
(and %{pkg:foo:enable} %{pkg:bar:enable})
false)
x
y)
-feature))))

View file

@ -0,0 +1,26 @@
Test the error message when curl is needed but not installed.
$ . ./helpers.sh
$ make_lockdir
$ makepkg() {
> make_lockpkg $1 <<EOF
> (source
> (fetch
> (url "http://0.0.0.0:8000")))
> (version dev)
> EOF
> }
$ makepkg foo
Build the package in an environment without curl.
$ PATH=$(dirname $(which dune)) build_pkg foo
File "dune.lock/foo.pkg", line 3, characters 7-28:
3 | (url "http://0.0.0.0:8000")))
^^^^^^^^^^^^^^^^^^^^^
Error: The program "curl" does not appear to be installed. Dune uses curl to
download packages. Dune requires that the "curl" executable be located in one
of the directories listed in the PATH variable.
Hint: Install curl with your system package manager.
[1]

View file

@ -0,0 +1,28 @@
Some environment variables are automatically exported by packages:
$ . ./helpers.sh
$ make_lockdir
$ echo "(version 0.0.1)" > dune.lock/test.pkg
$ cat >dune.lock/usetest.pkg <<'EOF'
> (version 0.0.1)
> (depends test)
> (build
> (system "\| echo MANPATH=$MANPATH
> "\| echo OCAMLPATH=$OCAMLPATH
> "\| echo CAML_LD_LIBRARY_PATH=$CAML_LD_LIBRARY_PATH
> "\| echo OCAMLTOP_INCLUDE_PATH=$OCAMLTOP_INCLUDE_PATH
> "\| echo PATH=$PATH
> ))
> EOF
$ mkdir .bin
$ ln -s $(which ocamlc) .bin/ocamlc
$ ln -s $(which sh) .bin/sh
$ dune=$(which dune)
$ MANPATH="" OCAMLPATH="" CAML_LD_LIBRARY_PATH="" OCAMLTOP_INCLUDE_PATH="" PATH="$PWD/.bin" build_pkg usetest
MANPATH=$TESTCASE_ROOT/_build/_private/default/.pkg/test/target/man
OCAMLPATH=$TESTCASE_ROOT/_build/_private/default/.pkg/test/target/lib
CAML_LD_LIBRARY_PATH=$TESTCASE_ROOT/_build/_private/default/.pkg/test/target/lib/stublibs
OCAMLTOP_INCLUDE_PATH=$TESTCASE_ROOT/_build/_private/default/.pkg/test/target/lib/toplevel
PATH=$TESTCASE_ROOT/_build/_private/default/.pkg/test/target/bin:$TESTCASE_ROOT/.bin

View file

@ -0,0 +1,46 @@
Modify the default branch of a source repo.
Once the branch is modified, dune should rebuild the package.
This bug is reported in #10063
$ . ../git-helpers.sh
$ . ./helpers.sh
$ src="_git_source"
$ mkdir $src && cd $src
$ git init --quiet
$ git checkout -b "branch1"
Switched to a new branch 'branch1'
$ echo "branch 1" > file
$ git add -A
$ git commit --quiet -m "branch 1"
$ git checkout -b branch2
Switched to a new branch 'branch2'
$ echo "branch 2" > file
$ git add -A
$ git commit --quiet -m "branch 2"
$ cd ..
$ make_lockdir
$ make_lockpkg foo <<EOF
> (source (fetch (url "git+file://$PWD/$src")))
> (version 0.0.1)
> (build (run cat file))
> EOF
Build the package
$ build_pkg foo
branch 2
Change the default branch
$ git -C $src checkout branch1
Switched to branch 'branch1'
And now rebuild
$ build_pkg foo
branch 1

View file

@ -0,0 +1,173 @@
Tests for the `dune describe pkg dependency-hash` command.
The case where there are no local packages:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> EOF
$ dune describe pkg dependency-hash
Error: No non-local dependencies
[1]
The case where there are local packages but no dependencies:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package (name a))
> (package (name b))
> EOF
$ dune describe pkg dependency-hash
Error: No non-local dependencies
[1]
The case where there are local packages with dependencies but no non-local
dependencies:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package (name a))
> (package
> (name b)
> (depends a))
> EOF
$ dune describe pkg dependency-hash
Error: No non-local dependencies
[1]
A single package with a single non-local dependency:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package
> (name a)
> (depends
> foo))
> EOF
$ dune describe pkg dependency-hash | tee hash1.txt
36e640fbcda71963e7e2f689f6c96c3e
Adding another dependency causes the hash to change:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package
> (name a)
> (depends
> foo
> bar))
> EOF
$ dune describe pkg dependency-hash | tee hash2.txt
b6404e14c268884f825aa1fb7d1b4ead
$ diff hash1.txt hash2.txt
1c1
< 36e640fbcda71963e7e2f689f6c96c3e
---
> b6404e14c268884f825aa1fb7d1b4ead
[1]
Adding a new local package which depends on one of the existing dependencies
changes the hash:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package
> (name a)
> (depends
> foo
> bar))
> (package
> (name b)
> (depends
> foo))
> EOF
$ dune describe pkg dependency-hash | tee hash3.txt
fa35416284004d71ff802a4c582f8797
$ diff hash2.txt hash3.txt
1c1
< b6404e14c268884f825aa1fb7d1b4ead
---
> fa35416284004d71ff802a4c582f8797
[1]
Adding a constraint to one of the dependencies causes the hash to change:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package
> (name a)
> (depends
> foo
> bar))
> (package
> (name b)
> (depends
> (foo (and :with-test (> 0.1)))))
> EOF
$ dune describe pkg dependency-hash | tee hash4.txt
fdf713b190b56d52d8cdbdd72a382654
$ diff hash3.txt hash4.txt
1c1
< fa35416284004d71ff802a4c582f8797
---
> fdf713b190b56d52d8cdbdd72a382654
[1]
Adding another local package with the same dependency and constraint changes
the hash:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package
> (name a)
> (depends
> foo
> bar))
> (package
> (name b)
> (depends
> (foo (and :with-test (> 0.1)))))
> (package
> (name c)
> (depends
> (foo (and :with-test (> 0.1)))))
> EOF
$ dune describe pkg dependency-hash | tee hash5.txt
38fa247158bdf36939ec8b10b3205508
$ diff hash4.txt hash5.txt
1c1
< fdf713b190b56d52d8cdbdd72a382654
---
> 38fa247158bdf36939ec8b10b3205508
[1]
Make sure that the hash changes when the formula changes from a conjunction to
a disjunction, thus changing the solution:
$ cat > dune-project <<EOF
> (lang dune 3.11)
> EOF
$ cat > local.opam <<EOF
> opam-version: "2.0"
> depends: [ "a" "b" ]
> EOF
$ dune describe pkg dependency-hash | tee hash-a-b.txt
d18946fdd9833ae312d309f654f11c1b
$ cat > local.opam <<EOF
> opam-version: "2.0"
> depends: [ "a" | "b" ]
> EOF
$ dune describe pkg dependency-hash | tee hash-a-or-b.txt
5b2db8d296a969fbd80033f70919b2ec
$ diff hash-a-and-b.txt hash-a-or-b.txt
diff: hash-a-and-b.txt: No such file or directory
[2]
The formula also changes if the dependencies being picked end up being the same
("a" and "b") but the formula changed by including another dependency:
$ cat > local.opam <<EOF
> opam-version: "2.0"
> depends: [ "a" & ("b" | "c") ]
> EOF
$ dune describe pkg dependency-hash | tee hash-a-b-or-c.txt
b704ac23e0d16a5e7a1b10aa6a8cbe0e
$ diff hash-a-b.txt hash-a-b-or-c.txt
1c1
< d18946fdd9833ae312d309f654f11c1b
---
> b704ac23e0d16a5e7a1b10aa6a8cbe0e
[1]

View file

@ -0,0 +1,61 @@
A package that installs itself into the ocaml stdlib should work.
$ . ./helpers.sh
$ mkdir nondune
$ cd nondune
$ cat > nondune.ml <<EOF
> let main () = print_endline "Nondune"
> let () = main ()
> EOF
$ ocamlc -c nondune.ml
$ ocamlc -o nondune.cma -a nondune.cmo
$ cat > nondune.install <<EOF
> lib_root: [
> "nondune.cma" {"ocaml/nondune.cma"}
> "nondune.cmi" {"ocaml/nondune.cmi"}
> ]
> lib: [
> "META" {"META"}
> ]
> EOF
$ cat > META <<EOF
> directory = "^"
> archive(byte) = "nondune.cma"
> EOF
$ cat > nondune.opam <<EOF
> opam-version: "2.0"
> build: [
> [true]
> ]
> EOF
$ cd ..
With this project set up, lets depend on it.
$ mkdir foo
$ cd foo
$ mkrepo
$ solve_project <<EOF
> (lang dune 3.15)
> (pin
> (url "file://$PWD/../nondune")
> (package (name nondune)))
> (package
> (name foo)
> (depends nondune))
> EOF
Solution for dune.lock:
- nondune.dev
$ cat > dune <<EOF
> (executable
> (name foo)
> (modules foo)
> (libraries nondune)
> (modes byte))
> EOF
$ cat > foo.ml <<EOF
> let () = Nondune.main ()
> EOF
$ dune exec ./foo.exe 2>&1 | grep -o "Unbound module Nondune"
Unbound module Nondune

View file

@ -0,0 +1,78 @@
When a package fails to build, dune will print opam depexts warning.
$ . ../helpers.sh
$ mkrepo
$ add_mock_repo_if_needed
Make a library that would fail when building it:
$ mkdir foo
$ cat > foo/dune-project <<EOF
> EOF
$ tar cf foo.tar foo
$ rm -rf foo
Make a project that uses the foo library:
$ cat > dune-project <<EOF
> (lang dune 3.13)
> (package
> (name bar)
> (depends foo))
> EOF
$ cat > dune <<EOF
> (executable
> (public_name bar)
> (libraries foo))
> EOF
Make dune.lock files with known program "dune".
$ make_lockdir
$ cat > dune.lock/foo.pkg <<EOF
> (version 0.0.1)
> (build
> (run dune build))
> (depexts unzip gnupg)
> (source
> (fetch
> (url file://$PWD/foo.tar)
> (checksum md5=$(md5sum foo.tar | cut -f1 -d' '))))
> EOF
Build the project, when it fails building 'foo' package, it shows the depexts
error message.
$ dune build
File "dune.lock/foo.pkg", line 3, characters 6-10:
3 | (run dune build))
^^^^
Error: Logs for package foo
File "dune-project", line 1, characters 0-0:
Error: Invalid first line, expected: (lang <lang> <version>)
Hint: You may want to verify the following depexts are installed:
- gnupg
- unzip
[1]
Make dune.lock files with unknown program and unknown package.
$ make_lockdir
$ cat > dune.lock/foo.pkg <<EOF
> (version 0.0.1)
> (build
> (run unknown-program))
> (depexts unknown-package)
> (source
> (fetch
> (url file://$PWD/foo.tar)
> (checksum md5=$(md5sum foo.tar | cut -f1 -d' '))))
> EOF
Running the same build. It is supposed to show the depexts message at the end,
when the program is not found.
$ dune build
File "dune.lock/foo.pkg", line 3, characters 6-21:
3 | (run unknown-program))
^^^^^^^^^^^^^^^
Error: Program unknown-program not found in the tree or in PATH
(context: default)
Hint: You may want to verify the following depexts are installed:
- unknown-package
[1]

View file

@ -0,0 +1,24 @@
Show that the depexts that a project has can be printed.
$ . ../helpers.sh
$ mkrepo
Make a project:
$ cat > dune-project <<EOF
> (lang dune 3.13)
> EOF
Create a lockdir with a package that features some depexts.
$ make_lockdir
$ cat > dune.lock/foo.pkg <<EOF
> (version 0.0.1)
> (depexts unzip gnupg)
> EOF
Printing the depexts should show all the depexts that the project has:
$ dune show depexts
gnupg
unzip

View file

@ -0,0 +1,27 @@
Solving would add opam 'depext' field to lock directory packages
$ . ../helpers.sh
$ mkrepo
$ add_mock_repo_if_needed
Make a package for the library with depexts:
$ mkpkg foo <<EOF
> depexts: [["unzip" "gnupg"]]
> EOF
Make a project that uses the foo library:
$ cat > dune-project <<EOF
> (lang dune 3.13)
> (package
> (name bar)
> (depends foo))
> EOF
locking would add the opam 'depext' field to foo.pkg
$ dune pkg lock
Solution for dune.lock:
- foo.0.0.1
$ cat dune.lock/foo.pkg
(version 0.0.1)
(depexts unzip gnupg)

View file

@ -0,0 +1,25 @@
Solving with an unknown variable on depexts:
$ . ../helpers.sh
$ mkrepo
$ add_mock_repo_if_needed
The "foobar" variable is not defined:
$ mkpkg foo <<EOF
> depexts: [[ "unzip" ] {foobar}]
> EOF
Make a project that uses the foo library:
$ cat > dune-project <<EOF
> (lang dune 3.13)
> (package
> (name bar)
> (depends foo))
> EOF
Locking should succeed and not include the "unzip" package
$ dune pkg lock 2>&1 | head -n 1
Solution for dune.lock:
$ [ -e dune.lock/foo.pkg ] && cat dune.lock/foo.pkg
(version 0.0.1)

View file

@ -0,0 +1,43 @@
Test that available optional dependencies of a package are added to the
"depends" field of that package's lockfile.
$ . ../helpers.sh
$ mkrepo
$ mkpkg a
$ mkpkg b
Make a package which has a regular dependency and an optional dependency.
$ mkpkg foo <<EOF
> depends: [ "a" ]
> depopts: [ "b" ]
> EOF
The optional dependency on "b" is not included in foo's dependencies because
"b" is not part of the package solution:
$ solve foo
Solution for dune.lock:
- a.0.0.1
- foo.0.0.1
$ cat dune.lock/foo.pkg
(version 0.0.1)
(depends a)
Another package which has a regular dependency on "b":
$ mkpkg bar <<EOF
> depends: [ "b" ]
> EOF
Solve again, this time depending on both "foo" and "bar". Now "b" is among
the dependencies of "foo", since "b" is part of the package solution:
$ solve foo bar
Solution for dune.lock:
- a.0.0.1
- b.0.0.1
- bar.0.0.1
- foo.0.0.1
$ cat dune.lock/foo.pkg
(version 0.0.1)
(depends a b)

View file

@ -0,0 +1,21 @@
This tests that depopts are considered optional by the solver.
$ . ../helpers.sh
$ mkrepo
$ mkpkg foo
$ mkpkg bar
We create a package that depends on foo and has an optional dependency on bar
but also a conflict with bar. This should ensure that bar is never selected by
the solver.
$ solve_project << EOF
> (lang dune 3.11)
> (package
> (name x)
> (depends foo)
> (depopts bar)
> (conflicts bar))
> EOF
Solution for dune.lock:
- foo.0.0.1

View file

@ -0,0 +1,23 @@
We test depopts with conflicting constraints to see which one the solver will
prefer if any:
$ . ../helpers.sh
$ mkpkg foo 1
$ mkpkg foo 2
$ mkpkg bar <<'EOF'
> depopts: [ "foo" {= "1"} ]
> EOF
$ mkpkg baz <<'EOF'
> depopts: [ "foo" {= "2"} ]
> EOF
We don't currently support depopts so they are both omitted.
$ solve bar baz
Solution for dune.lock:
- bar.0.0.1
- baz.0.0.1
It's possible to find a solution by satisfying one (but not both) depopts.

View file

@ -0,0 +1,39 @@
We test how the solver chooses a solution for depopts with constraints.
$ . ../helpers.sh
$ mkrepo
We create a package "foo" that is the dependency of two packages "optional" and
"bar".
$ mkpkg foo 1
The package "optional" has a constraint on a particular version of "foo".
$ mkpkg optional <<'EOF'
> depends: [ "foo" {= "1"} ]
> EOF
The package "bar" depends on "foo" and depends optionally on "optional".
$ mkpkg bar <<'EOF'
> depends: [ "foo" ]
> depopts: [ "optional" ]
> EOF
Here the solver could pick "bar" and "foo", and perphaps pick "optional",
however this is not required.
$ solve bar
Solution for dune.lock:
- bar.0.0.1
- foo.1
Since the version of "foo" is constrained by "optional", "optional" should be
excluded from the build plan if the latest version of "foo" is picked.
$ mkpkg foo 2
$ solve bar
Solution for dune.lock:
- bar.0.0.1
- foo.2

View file

@ -0,0 +1,16 @@
Selecting depopts
$ . ../helpers.sh
$ mkrepo
$ mkpkg foo
$ mkpkg bar
$ solve_project << EOF
> (lang dune 3.11)
> (package
> (name x)
> (depends foo)
> (depopts bar))
> EOF
Solution for dune.lock:
- foo.0.0.1

View file

@ -0,0 +1,43 @@
Reproduce github issue #11058
Handling of more than one depopt:
$ . ../helpers.sh
$ mkpkg a
$ mkpkg b
$ mkpkg c
$ mkpkg d
$ mkpkg e
$ mkpkg f
$ runtest() {
> mkpkg bar <<'EOF'
> depopts: [ "a" "b" "c" ]
> EOF
> solve bar
> }
$ runtest <<'EOF'
> depopts: [ "a" "b" "c" ]
> EOF
Solution for dune.lock:
- bar.0.0.1
$ runtest <<'EOF'
> depopts: [ "a" "b" "c" "d" ]
> EOF
Solution for dune.lock:
- bar.0.0.1
$ runtest <<'EOF'
> depopts: [ ("a" | "b") "c" "d" ]
> EOF
Solution for dune.lock:
- bar.0.0.1
$ runtest <<'EOF'
> depopts: [ (("e" | "a") | ("d" | "f")) "b" "c" ]
> EOF
Solution for dune.lock:
- bar.0.0.1

View file

@ -0,0 +1,31 @@
Reproduce the bug in #11698
$ . ../helpers.sh
$ mkrepo
$ add_mock_repo_if_needed
$ mkpkg fmt
$ mkpkg semver
$ mkdir _dep
$ cat >_dep/dune-project <<EOF
> (lang dune 3.18)
> (package
> (name dep)
> (depopts fmt semver))
> EOF
$ solve_project <<EOF
> (lang dune 3.18)
> (pin
> (url "file://$PWD/_dep")
> (package
> (name dep)
> (version 1.0.0)))
> (package
> (name x)
> (depends dep))
> EOF
Solution for dune.lock:
- dep.1.0.0

View file

@ -0,0 +1,38 @@
We test how opam files with depopts fields are translated into dune.lock files:
$ . ../helpers.sh
$ mkrepo
Make a package with a depopts field
$ mkpkg with-depopts <<'EOF'
> depopts: [ "foo" ]
> EOF
$ mkpkg foo
$ solve with-depopts
Solution for dune.lock:
- with-depopts.0.0.1
When depopts are supported and selected, the above lock should change and we
should also be able to see a deps field in the lock file:
$ cat dune.lock/with-depopts.pkg
(version 0.0.1)
We should also be able to validate the lock directory:
$ dune pkg validate-lockdir
Depopts should not be selected if they conflict with other constraints:
$ mkpkg no-foo <<'EOF'
> depends: [ "with-depopts" ]
> conflicts: [ "foo" ]
> EOF
$ solve no-foo
Solution for dune.lock:
- no-foo.0.0.1
- with-depopts.0.0.1
$ dune pkg validate-lockdir

View file

@ -0,0 +1,87 @@
Demonstrate how depopts can be forced in the workspace
$ . ../helpers.sh
$ mkrepo
$ mkpkg foo
$ mkpkg bar
$ mkpkg baz
$ solve_project <<EOF
> (lang dune 3.18)
> (package
> (name x)
> (depopts foo bar))
> EOF
Solution for dune.lock:
(no dependencies to lock)
Select just foo
$ cat >dune-workspace <<EOF
> (lang dune 3.10)
> (lock_dir
> (depopts foo)
> (repositories mock))
> (repository
> (name mock)
> (url "file://$PWD/mock-opam-repository"))
> EOF
$ dune pkg lock
Solution for dune.lock:
- foo.0.0.1
Select both foo and bar
$ cat >dune-workspace <<EOF
> (lang dune 3.10)
> (lock_dir
> (depopts foo bar)
> (repositories mock))
> (repository
> (name mock)
> (url "file://$PWD/mock-opam-repository"))
> EOF
$ dune pkg lock
Solution for dune.lock:
- bar.0.0.1
- foo.0.0.1
Select a package that is not listed as depopt
$ cat >dune-workspace <<EOF
> (lang dune 3.10)
> (lock_dir
> (depopts baz)
> (repositories mock))
> (repository
> (name mock)
> (url "file://$PWD/mock-opam-repository"))
> EOF
$ dune pkg lock
Solution for dune.lock:
(no dependencies to lock)
Select garbage
$ cat >dune-workspace <<EOF
> (lang dune 3.10)
> (lock_dir
> (depopts z)
> (repositories mock))
> (repository
> (name mock)
> (url "file://$PWD/mock-opam-repository"))
> EOF
$ dune pkg lock
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
The following packages couldn't be found: z
[1]

View file

@ -0,0 +1,74 @@
$ . ./helpers.sh
$ mkrepo
Testing the output of the dune describe pkg lock command.
First we setup a repo.
$ mkpkg A 1.2.0
> mkpkg B 2.1+rc1
> mkpkg C 81.0.4044.138 <<EOF
> depends: [ "D" "E" ]
> EOF
> mkpkg D 0.4.0.beta1
> mkpkg E 3.0~alpha1
$ cat > dune-workspace <<EOF
> (lang dune 3.11)
> (context
> (default))
> (context
> (default
> (name "foo")
> (lock_dir foo.lock)))
> (lock_dir
> (repositories mock))
> (lock_dir
> (path foo.lock)
> (repositories mock))
> (repository
> (name mock)
> (url "file://$(pwd)/mock-opam-repository"))
> EOF
Here is the output of solving for multiple contexts:
$ solve_project --all <<EOF
> (lang dune 3.11)
> (package
> (name x)
> (depends A B C))
> EOF
Solution for dune.lock:
- A.1.2.0
- B.2.1+rc1
- C.81.0.4044.138
- D.0.4.0.beta1
- E.3.0~alpha1
Solution for foo.lock:
- A.1.2.0
- B.2.1+rc1
- C.81.0.4044.138
- D.0.4.0.beta1
- E.3.0~alpha1
Here is the output of dune describe pkg lock:
$ dune describe pkg lock
Contents of dune.lock:
- A.1.2.0
- B.2.1+rc1
- C.81.0.4044.138
- D.0.4.0.beta1
- E.3.0~alpha1
The names of the lockfiles can also be provided:
$ dune describe pkg lock dune.lock foo.lock
Contents of dune.lock:
- A.1.2.0
- B.2.1+rc1
- C.81.0.4044.138
- D.0.4.0.beta1
- E.3.0~alpha1
Contents of foo.lock:
- A.1.2.0
- B.2.1+rc1
- C.81.0.4044.138
- D.0.4.0.beta1
- E.3.0~alpha1

View file

@ -0,0 +1,59 @@
Exercise printing the help messages for dev tools commands.
Disable the pagers, as the command line parser might use a pager from the users
system which will reformat the output if not specifically requesting `plain`
output.
$ export PAGER=false
$ export MANPAGER=false
Output the help text:
$ dune tools exec --help=plain
NAME
dune-tools-exec - Command group for running wrapped tools.
SYNOPSIS
dune tools exec COMMAND
COMMANDS
ocamlearlybird [OPTION] [ARGS]
Wrapper for running ocamlearlybird intended to be run
automatically by a text editor. All positional arguments will be
passed to the ocamlearlybird executable (pass flags to
ocamlearlybird after the '--' argument, such as 'dune tools exec
ocamlearlybird -- --help').
ocamlformat [OPTION] [ARGS]
Wrapper for running ocamlformat intended to be run automatically
by a text editor. All positional arguments will be passed to the
ocamlformat executable (pass flags to ocamlformat after the '--'
argument, such as 'dune tools exec ocamlformat -- --help').
ocamllsp [OPTION] [ARGS]
Wrapper for running ocamllsp intended to be run automatically by a
text editor. All positional arguments will be passed to the
ocamllsp executable (pass flags to ocamllsp after the '--'
argument, such as 'dune tools exec ocamllsp -- --help').
COMMON OPTIONS
--help[=FMT] (default=auto)
Show this help in format FMT. The value FMT must be one of auto,
pager, groff or plain. With auto, the format is pager or plain
whenever the TERM env var is dumb or undefined.
--version
Show version information.
EXIT STATUS
dune tools exec exits with:
0 on success.
1 if an error happened.
130 if it was interrupted by a signal.
SEE ALSO
dune(1)

View file

@ -0,0 +1,82 @@
Clarify the behavior when the `dune` in PATH is not the one used to start the build.
$ . ./helpers.sh
$ make_test_package() {
> mkdir tmp
> cd tmp
> cat > dune-project <<EOF
> (lang dune 3.13)
> (package
> (name $1)
> (allow_empty))
> EOF
> cd ..
> tar cf $1.tar tmp
> rm -rf tmp
> }
$ make_test_package foo
$ make_test_package bar
Make a project that depends on the test packages:
$ cat > dune-project <<EOF
> (lang dune 3.13)
> (package
> (name x)
> (allow_empty)
> (depends foo bar))
> EOF
$ cat > dune <<EOF
> (data_only_dirs bin)
> EOF
Make lockfiles for the packages.
$ make_lockdir
$ make_lockpkg foo <<EOF
> (version 0.0.1)
>
> (build
> (run dune build -p %{pkg-self:name} @install))
>
> (source
> (fetch
> (url $PWD/foo.tar)))
>
> (dev)
> EOF
$ make_lockpkg bar <<EOF
> (version 0.0.1)
>
> (build
> ; Exercise that the dune exe can be located when it's launched by a subprocess.
> (run sh -c "dune build -p %{pkg-self:name} @install"))
>
> (source
> (fetch
> (url $PWD/bar.tar)))
>
> (dev)
> EOF
Test that the project can be built normally.
$ build_pkg foo
Make a fake dune exe:
$ mkdir bin
$ cat > bin/dune <<EOF
> #!/bin/sh
> echo "Fake dune! (args: \$@)"
> EOF
$ chmod a+x bin/dune
$ dune clean
Try building in an environment where `dune` refers to the fake dune.
$ DUNE=$(which dune) # otherwise we would start by running the wrong dune
$ PATH=$PWD/bin:$PATH $DUNE build $pkg_root/foo/target/
Fake dune! (args: build -p foo @install)
$ PATH=$PWD/bin:$PATH $DUNE build $pkg_root/bar/target/
Fake dune! (args: build -p bar @install)

View file

@ -0,0 +1,80 @@
(cram
(alias pkg)
(applies_to :whole_subtree))
(env
(_
(env-vars
(DUNE_DEBUG_PACKAGE_LOGS 1))))
(cram
(deps helpers.sh %{bin:git} ../git-helpers.sh)
(applies_to :whole_subtree))
(cram
(deps %{bin:patch})
(applies_to patch opam-package-with-patch extra-sources))
(cram
(applies_to rev-store-lock-linux)
(enabled_if
(= %{system} linux))
(deps %{bin:strace}))
(cram
(deps %{bin:awk} %{bin:cmp})
(applies_to git-repo))
(cram
(deps %{bin:make})
(applies_to make))
(cram
(deps %{bin:which})
(applies_to pkg-deps))
(cram
(deps %{bin:curl})
(applies_to
unavailable-source-package
compute-checksums-when-missing
e2e
ocamlformat-dev-tool
source-caching
tarball
pin-depends
extra-sources
broken-symlink-in-dependency))
(cram
(deps %{bin:md5sum})
(applies_to
source-caching
extra-sources
ocamlformat-dev-tool
dev-tool-conflict-test
broken-symlink-in-dependency))
(cram
(deps %{bin:tar})
(applies_to
source-caching
tarball
pin-depends
extra-sources
pkg-extract-fail
broken-symlink-in-dependency))
(cram
(deps %{bin:ocaml_index})
(applies_to gh10985))
(cram
(deps %{bin:unzip})
(applies_to pkg-extract-fail))
;; disabled for flakiness
(cram
(enabled_if false)
(applies_to gh10959))

View file

@ -0,0 +1,20 @@
We configure the same lock directory twice:
$ cat >dune-workspace <<EOF
> (lang dune 3.11)
> (lock_dir (path foo))
> (lock_dir (path foo))
> EOF
$ dune build
Another way to define a duplicate is by omitting the path. Since it defaults to
dune.lock:
$ cat >dune-workspace <<EOF
> (lang dune 3.11)
> (lock_dir)
> (lock_dir (path dune.lock))
> EOF
$ dune build

View file

@ -0,0 +1,30 @@
A workspace with a package that exists in the lock file and in the workspace
shouldn't be allowed (for now)
$ . ./helpers.sh
$ cat >dune-project <<EOF
> (lang dune 3.11)
> EOF
$ cat > mypkg.opam <<EOF
> opam-version: "2.0"
> EOF
$ mkdir dune.lock
$ cat >dune.lock/lock.dune <<EOF
> (lang package 0.1)
> EOF
$ touch dune.lock/mypkg.lock
$ dune build
It should also fail when we define the package only in the dune-project file:
$ rm mypkg.opam
$ cat >>dune-project <<EOF
> (package
> (allow_empty)
> (name mypkg))
> EOF
$ dune build

View file

@ -0,0 +1,17 @@
Duplicate repository definition in the same workspace file:
$ cat >dune-workspace <<EOF
> (lang dune 3.11)
> (repository
> (name foo)
> (url "git+file//$PWD/foo"))
> (repository
> (name foo)
> (url "git+file//$PWD/foo"))
> EOF
$ dune pkg outdated 2>&1 | awk '/Internal error/,/Raised/'
Internal error, please report upstream including the contents of _build/log.
Description:
("Map.of_list_exn", { key = "foo" })
Raised at Stdune__Code_error.raise in file

View file

@ -0,0 +1,79 @@
Exercises end to end locking and building a simple project.
$ . ./helpers.sh
$ mkrepo
$ add_mock_repo_if_needed
Make a library:
$ mkdir foo
$ cd foo
$ cat > dune-project <<EOF
> (lang dune 3.13)
> (package (name foo))
> EOF
$ cat > foo.ml <<EOF
> let foo = "Hello, World!"
> EOF
$ cat > dune <<EOF
> (library
> (public_name foo))
> EOF
$ cd ..
$ tar cf foo.tar foo
$ rm -rf foo
Configure our fake curl to serve the tarball
$ echo foo.tar >> fake-curls
$ PORT=1
Make a package for the library:
$ mkpkg foo <<EOF
> build: [
> ["dune" "subst"] {dev}
> [
> "dune"
> "build"
> "-p"
> name
> "-j"
> jobs
> "@install"
> "@runtest" {with-test}
> "@doc" {with-doc}
> ]
> ]
> url {
> src: "http://0.0.0.0:$PORT"
> checksum: [
> "md5=$(md5sum foo.tar | cut -f1 -d' ')"
> ]
> }
> EOF
Make a project that uses the library:
$ cat > dune-project <<EOF
> (lang dune 3.13)
> (package
> (name bar)
> (depends foo))
> EOF
$ cat > bar.ml <<EOF
> let () = print_endline Foo.foo
> EOF
$ cat > dune <<EOF
> (executable
> (public_name bar)
> (libraries foo))
> EOF
Lock, build, and run the executable in the project:
$ dune pkg lock
Solution for dune.lock:
- foo.0.0.1
$ dune exec bar
Hello, World!

View file

@ -0,0 +1,66 @@
$ . ./helpers.sh
$ mkrepo
A package with different linux and macos dependencies including a test-only
dependency:
$ mkpkg foo <<EOF
> depends: [
> "foo-linux" {os = "linux"}
> "foo-macos" {os = "macos"}
> "foo-macos-test-only" {os = "macos" & with-test}
> ]
> EOF
$ mkpkg foo-linux <<EOF
> available: os = "linux"
> EOF
$ mkpkg foo-linux-test-only <<EOF
> available: os = "linux"
> EOF
$ mkpkg foo-macos <<EOF
> available: os = "macos"
> EOF
Create a workspace config that defines separate build contexts for macos and linux.
$ cat >dune-workspace <<EOF
> (lang dune 3.8)
> (lock_dir
> (path dune.no-os.lock)
> (repositories mock)
> (solver_env
> (unset_variables os)))
> (lock_dir
> (path dune.linux.lock)
> (repositories mock)
> (solver_env
> (os linux)))
> (lock_dir
> (path dune.macos.lock)
> (repositories mock)
> (solver_env
> (os macos)))
> (lock_dir
> (path dune.lock)
> (repositories mock))
> (context
> (default
> (name linux)
> (lock_dir dune.linux.lock)))
> (context
> (default
> (name macos)
> (lock_dir dune.macos.lock)))
> (repository
> (name mock)
> (url "file://$(pwd)/mock-opam-repository"))
> EOF
Now the os-specific dependencies are included on their respective systems.
$ dune pkg lock --all
Solution for dune.linux.lock:
(no dependencies to lock)
Solution for dune.lock:
(no dependencies to lock)
Solution for dune.macos.lock:
(no dependencies to lock)
Solution for dune.no-os.lock:
(no dependencies to lock)

View file

@ -0,0 +1,24 @@
Test for packages with no source field but with extra_sources.
$ . ./helpers.sh
$ make_lockdir
$ cat > dune.lock/foo.pkg <<EOF
> (version 1)
> (extra_sources
> (foo.txt
> (fetch
> (url file://$PWD/foo.txt))))
> EOF
$ touch foo.txt
$ cat > dune-project <<EOF
> (lang dune 3.16)
> (package
> (allow_empty)
> (name a)
> (depends foo))
> EOF
$ dune build

View file

@ -0,0 +1,32 @@
Packages can export environment variables
$ . ./helpers.sh
$ make_lockdir
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (exported_env
> (= FOO bar)
> (= BAR xxx)
> (+= BAR yyy)
> (:= BAR zzz))
> EOF
$ cat >dune.lock/usetest.pkg <<'EOF'
> (depends test)
> (version 1.2.3)
> (build
> (progn
> (system "\| echo FOO=$FOO
> "\| echo BAR=$BAR
> "\| echo OPAM_PACKAGE_NAME=$OPAM_PACKAGE_NAME
> "\| echo OPAM_PACKAGE_VERSION=$OPAM_PACKAGE_VERSION
> )
> (run mkdir -p %{prefix})))
> EOF
$ build_pkg usetest
FOO=bar
BAR=zzz:yyy:xxx
OPAM_PACKAGE_NAME=usetest
OPAM_PACKAGE_VERSION=1.2.3

View file

@ -0,0 +1,24 @@
A lock directory which does not exist in the source tree:
$ . ./helpers.sh
$ mkdir dune.lock project
$ cat >dune.lock/foo.pkg <<EOF
> (build (run echo foo))
> (version 1.0.0)
> EOF
$ cat >dune-workspace <<EOF
> (lang dune 3.13)
> (lock_dir (path $PWD/dune.lock))
> EOF
$ build_pkg foo 2>&1 | awk '/Internal error/,/Raised/'
Internal error, please report upstream including the contents of _build/log.
Description:
("Local.relative: received absolute path",
{ t = "."
; path =
"$TESTCASE_ROOT/dune.lock"
})
Raised at Stdune__Code_error.raise in file

View file

@ -0,0 +1,27 @@
Test that can fetch the sources from an external dir
$ . ./helpers.sh
$ mkdir foo
$ echo "y" > foo/x
$ make_lockdir
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (source (copy $PWD/foo))
> (build
> (progn
> (run mkdir -p %{prefix}/bin)
> (run cp x %{prefix}/bin/x)))
> EOF
$ build_pkg test
$ show_pkg test
/source
/source/x
/target
/target/bin
/target/bin/x
/target/cookie

View file

@ -0,0 +1,35 @@
Test for packages with an extra-source file with the same name as a
file in the package's source.
$ . ./helpers.sh
$ make_lockdir
$ cat > dune.lock/foo.pkg <<EOF
> (version 1)
> (source
> (copy $PWD/foo-source))
> (extra_sources
> (foo.txt
> (fetch
> (url file://$PWD/foo.txt))))
> EOF
$ mkdir -p foo-source
$ echo "from source" > foo-source/foo.txt
$ echo "from extra source" > foo.txt
$ cat > dune-project <<EOF
> (lang dune 3.16)
> (package
> (allow_empty)
> (name a)
> (depends foo))
> EOF
$ build_pkg foo
Make sure that the package's source directory ends up with the version
of foo.txt from extra_sources:
$ cat _build/_private/default/.pkg/foo/source/foo.txt
from extra source

View file

@ -0,0 +1,178 @@
Fetch from more than one source
$ . ../git-helpers.sh
$ . ./helpers.sh
$ make_lockdir
$ mkdir foo
$ cat >foo/bar <<EOF
> this is bar
> EOF
$ cat >baz <<EOF
> this is baz
> EOF
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (source (copy $PWD/foo))
> (extra_sources (mybaz (copy $PWD/baz)))
> (build
> (system "find . | sort -u"))
> EOF
$ build_pkg test
.
./bar
./mybaz
Make sure extra source patches are downloaded, checksum-verified and applied
when building.
First we need a project that will have the patch applied:
$ mkdir needs-patch
$ cd needs-patch
$ git init --quiet
$ cat > dune-project <<EOF
> (lang dune 3.15)
> (name needs-patch)
> EOF
$ cat > needs-patch.opam <<EOF
> opam-version: "2.0"
> EOF
$ cat > dune <<EOF
> (library (public_name needs-patch) (name needs_patch))
> EOF
$ cat > needs_patch.ml <<EOF
> let msg = "Needs to be patched"
> EOF
$ cd ..
$ tar cf needs-patch.tar needs-patch
$ SRC_MD5=$(md5sum needs-patch.tar | cut -f1 -d' ')
$ cd needs-patch
$ git add -A
$ git commit -m "Initial" --quiet
$ cat > needs_patch.ml <<EOF
> let msg = "Patch successfully applied"
> EOF
$ git diff > ../required.patch
$ git add needs_patch.ml
$ git commit -m "First patch" --quiet
$ cat > needs_patch.ml <<EOF
> let msg = "Patch successfully applied, multiple times"
> EOF
$ git diff > ../additional.patch
$ cd ..
$ rm -rf needs-patch
$ REQUIRED_PATCH_MD5=$(md5sum required.patch | cut -f1 -d' ')
$ ADDITIONAL_PATCH_MD5=$(md5sum additional.patch | cut -f1 -d' ')
Then we start the oneshot server for both the source and the patch.
$ echo needs-patch.tar > fake-curls
$ SRC_PORT=1
$ echo required.patch >> fake-curls
$ REQUIRED_PATCH_PORT=2
We now have the checksums as well as the port numbers, so we can define the
package.
$ mkrepo
$ mkpkg needs-patch 0.0.1 <<EOF
> build: ["dune" "build" "-p" name "-j" jobs]
> patches: ["required.patch"]
> url {
> src: "http://localhost:$SRC_PORT"
> checksum: "md5=$SRC_MD5"
> }
> extra-source "required.patch" {
> src: "http://localhost:$REQUIRED_PATCH_PORT"
> checksum: "md5=$REQUIRED_PATCH_MD5"
> }
> EOF
Now let's depend on that project with a binary that will display the message
that is supposed to get patched.
$ cat > dune-project <<EOF
> (lang dune 3.15)
> (package (name my) (depends needs-patch))
> EOF
$ cat > dune <<EOF
> (executable (public_name display) (libraries needs-patch))
> EOF
$ cat > display.ml <<EOF
> let () = print_endline Needs_patch.msg
> EOF
Lock the dependency, it should generate an a lock dir that references both the
url and the extra source.
$ add_mock_repo_if_needed
$ dune pkg lock
Solution for dune.lock:
- needs-patch.0.0.1
$ sed -E 's/md5=[0-9a-f]+/md5=$HASH/g' dune.lock/needs-patch.pkg
(version 0.0.1)
(build
(progn
(patch required.patch)
(run dune build -p %{pkg-self:name} -j %{jobs})))
(source
(fetch
(url http://localhost:1)
(checksum md5=$HASH)))
(extra_sources
(required.patch
(fetch
(url http://localhost:2)
(checksum md5=$HASH))))
Running the binary should download the tarball & patch, build them and show the
correct, patched, message:
$ dune exec ./display.exe
Patch successfully applied
Set up a new version of the package which has multiple `extra-sources`, the
application order of them mattering:
$ echo needs-patch.tar >> fake-curls
$ SRC_PORT=3
$ echo required.patch >> fake-curls
$ REQUIRED_PATCH_PORT=4
$ echo additional.patch >> fake-curls
$ ADDITIONAL_PATCH_PORT=5
$ mkpkg needs-patch 0.0.2 <<EOF
> build: ["dune" "build" "-p" name "-j" jobs]
> patches: ["required.patch" "additional.patch"]
> url {
> src: "http://localhost:$SRC_PORT"
> checksum: "md5=$SRC_MD5"
> }
> extra-source "required.patch" {
> src: "http://localhost:$REQUIRED_PATCH_PORT"
> checksum: "md5=$REQUIRED_PATCH_MD5"
> }
> extra-source "additional.patch" {
> src: "http://localhost:$ADDITIONAL_PATCH_PORT"
> checksum: "md5=$ADDITIONAL_PATCH_MD5"
> }
> EOF
Lock the project to use that new package
$ dune pkg lock
Solution for dune.lock:
- needs-patch.0.0.2
Running the binary should work and output the double patched message:
$ dune exec ./display.exe
Patch successfully applied, multiple times

View file

@ -0,0 +1,60 @@
Testing that files are only fetched once.
$ . ./helpers.sh
No need to set DUNE_CACHE (enabled by default) as the
fetch rules are always considered safe to cache, but we'll set a custom
directory for the shared cache.
$ export DUNE_CACHE_ROOT=$(pwd)/dune-cache
$ unset DUNE_CACHE
Set up a project that depends on a package that is being downloaded
$ make_lockdir
$ echo "Contents" > tar-contents
$ CONTENT_CHECKSUM=$(md5sum tar-contents | cut -f1 -d' ')
$ tar cf test.tar tar-contents
$ echo test.tar > fake-curls
$ SRC_PORT=1
$ SRC_CHECKSUM=$(md5sum test.tar | cut -f1 -d' ')
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (source
> (fetch
> (url http://localhost:$SRC_PORT)
> (checksum md5=$SRC_CHECKSUM)))
> EOF
$ cat > dune-project <<EOF
> (lang dune 3.17)
> (package (name my) (depends test) (allow_empty))
> EOF
The first build should succeed, fetching the source, populating the cache and
disabling the download of the source a second time.
$ build_pkg test
Make sure that the file that was fetched is in the cache:
$ find $DUNE_CACHE_ROOT/files -type f -exec md5sum {} \; | grep --quiet $CONTENT_CHECKSUM
Cleaning the project to force rebuilding. If we attempt to build without the
cache, it will fail, as the source is 404 now:
$ dune clean
$ export DUNE_CACHE=disabled
$ build_pkg test
File "dune.lock/test.pkg", line 4, characters 7-25:
4 | (url http://localhost:1)
^^^^^^^^^^^^^^^^^^
Error: download failed with code 404
[1]
However when enabling the cache again, the file that was fetched in the first
build should be retrieved from the cache and the build succeed:
$ dune clean
$ export DUNE_CACHE=enabled
$ build_pkg test

View file

@ -0,0 +1,42 @@
Test that dune can fetch local sources.
$ . ./helpers.sh
$ mkrepo
Make a local source archive:
$ mkdir src
$ echo hello > src/a.txt
$ echo world > src/b.txt
$ tar -czf src.tar.gz src
Build a package that uses the archive as its source:
$ mkpkg foo <<EOF
> url {
> src: "$PWD/src.tar.gz"
> }
> EOF
$ add_mock_repo_if_needed
$ solve foo
Solution for dune.lock:
- foo.0.0.1
$ build_pkg foo
$ cat _build/_private/default/.pkg/foo/source/*
hello
world
$ dune clean
Build a package that uses the src directory as its source:
$ mkpkg foo <<EOF
> url {
> src: "$PWD/src"
> }
> EOF
$ add_mock_repo_if_needed
$ solve foo
Solution for dune.lock:
- foo.0.0.1
$ build_pkg foo
$ cat _build/_private/default/.pkg/foo/source/*
hello
world

View file

@ -0,0 +1,62 @@
Here we test the file-depends field in pkg1.config. When a package has been
installed, the .config file can also be included. This can have a file-depends
field which is a list of external files, together with their checksums, that
the package depends on. We make sure that such a package really does depend on
the files found in files-depend.
$ . ./helpers.sh
$ make_lockdir
$ foo=$PWD/foo
> cat > dune.lock/file-depends.pkg <<EOF
> (version 0.0.1)
> (build
> (system "\| echo Building file-depends
> "\| cat > file-depends.config <<EOF
> "\| opam-version: "2.0"
> "\| file-depends: [ "$foo" "md5=00000000000000000000000000000000" ]
> "\| EOF
> ))
> EOF
Word of warning: the opam libraries will quietly discard the file-depends field if the
checksum is not parsable.
Now we make a package depending on file-depends.
$ cat > dune.lock/dep.pkg <<EOF
> (version 0.0.1)
> (depends file-depends)
> (build
> (system "echo Building dep"))
> EOF
$ cat > foo <<EOF
> Hello
> EOF
Building dep should show both of them as being built.
$ build_pkg dep
Building file-depends
Building dep
Building again causes no rebuild as expected.
$ build_pkg dep
Changing foo should cause foo to be rebuilt.
$ cat > foo <<EOF
> World
> EOF
CR-someday alizter: This is broken, no rebuild is done.
$ build_pkg dep
Removing foo should cause an error due to the missing file.
$ rm foo
CR-someday alizter: This is broken, no rebuild is done.
$ build_pkg dep

View file

@ -0,0 +1,74 @@
Demonstrate the handling of findlib directories that don't exist
Reproduces #11405
$ . ./helpers.sh
$ mkdir external_sources
$ cat >external_sources/META <<EOF
> package "yes" (
> directory = "yes"
> version = "0.0.1"
> exists_if = "yes.cma"
> )
> package "no" (
> directory = "no"
> version = "0.0.1"
> exists_if = "no.cma"
> )
> EOF
$ cat >external_sources/mypkg.install <<EOF
> lib: [
> "META"
> "yes/yes.cma" {"yes/yes.cma"}
> ]
> EOF
$ mkdir external_sources/yes
$ touch external_sources/yes/yes.cma
$ cat >dune-project <<EOF
> (lang dune 3.17)
> EOF
$ mkdir dune.lock
$ cat >dune.lock/lock.dune <<EOF
> (lang package 0.1)
> EOF
$ cat >dune.lock/mypkg.pkg <<EOF
> (version 0.0.1)
> (source (copy $PWD/external_sources))
> EOF
$ touch foo.ml
$ cat >dune <<EOF
> (executable
> (libraries mypkg.yes)
> (name foo))
> EOF
No errors here as 'yes' actually exists
$ dune build foo.exe
$ cat >dune <<EOF
> (executable
> (libraries mypkg.no)
> (name foo))
> EOF
Clearer error here as we really depend on non-existing 'no'
$ dune build foo.exe
File "dune", line 2, characters 12-20:
2 | (libraries mypkg.no)
^^^^^^^^
Error: Library "mypkg.no" in
_build/_private/default/.pkg/mypkg/target/lib/mypkg/no is hidden (unsatisfied
'exists_if').
-> required by _build/default/.foo.eobjs/native/dune__exe__Foo.cmx
-> required by _build/default/foo.exe
[1]

View file

@ -0,0 +1,63 @@
Repro `dune exec --watch` crash with pkg management
$ . ./helpers.sh
$ mkdir external_sources
$ cat >external_sources/dune-project <<EOF
> (lang dune 3.11)
> (package (name mypkg))
> EOF
$ cat >external_sources/dune <<EOF
> (library
> (public_name mypkg.lib)
> (name test_lib))
> EOF
$ cat >external_sources/test_lib.ml <<EOF
> let x = "hello"
> EOF
Now we set up a lock file with this package and then attempt to use it:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> EOF
$ mkdir dune.lock
$ cat >dune.lock/lock.dune <<EOF
> (lang package 0.1)
> EOF
$ cat >dune.lock/mypkg.pkg <<EOF
> (version 0.0.1)
> (source (copy $PWD/external_sources))
> (build
> (run dune build --release --promote-install-file=true . @install))
> EOF
$ cat >dune <<EOF
> (dirs (:standard \ external_sources))
> (executable
> (name x)
> (libraries mypkg.lib))
> EOF
$ cat >x.ml <<EOF
> let () = print_endline Test_lib.x
> EOF
$ dune exec -w ./x.exe > output.log 2>&1 &
$ PID=$!
$ TIME_WAITED=0
$ MAX_WAIT_TIME=20
$ SLEEP_INTERVAL=1
$ while [ $(cat output.log | wc -l) -lt 2 ] && [ "$TIME_WAITED" -lt "$MAX_WAIT_TIME" ]; do
> sleep 0.1
> TIME_WAITED=$((TIME_WAITED + SLEEP_INTERVAL))
> done
$ cat output.log | sort
Success, waiting for filesystem changes...
hello
$ kill $PID
$ wait $PID

View file

@ -0,0 +1,64 @@
This test attempts to build the ocaml index while depending on a library
installed through a lock file.
We set up a library that will be installed as part of the package:
$ mkdir external_sources
$ cat >external_sources/dune-project <<EOF
> (lang dune 3.11)
> (package (name mypkg))
> EOF
$ cat >external_sources/dune <<EOF
> (library
> (public_name mypkg.lib)
> (name test_lib))
> EOF
$ cat >external_sources/test_lib.ml <<EOF
> let x = ()
> EOF
We put the actual build in a separate directory, so we don't have to ignore
the package directory in the dune file:
$ mkdir actual
$ cd actual
Now we set up a lock file with this package and then attempt to use it:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> EOF
$ mkdir dune.lock
$ cat >dune.lock/lock.dune <<EOF
> (lang package 0.1)
> EOF
$ cat >dune.lock/mypkg.pkg <<EOF
> (version 0.0.1)
> (source (copy $PWD/../external_sources))
> (build (run dune build --release --promote-install-file=true . @install))
> EOF
$ cat >dune <<EOF
> (library
> (name foo)
> (libraries mypkg.lib))
> EOF
$ cat >foo.ml <<EOF
> let () = Test_lib.x
> EOF
$ mkdir .bin
$ cat > .bin/ocaml-index <<EOF
> #!/usr/bin/env sh
> exit 1
> EOF
$ chmod +x .bin/ocaml-index
$ export PATH="$PWD/.bin:$PATH"
$ dune build @ocaml-index
File ".foo.objs/_unknown_", line 1, characters 0-0:
Command exited with code 1.
[1]

View file

@ -0,0 +1,42 @@
Package conflicts are ignored when dune-projects contains multiple conflicts
$ . ./helpers.sh
$ mkrepo
$ mkpkg bar
A package which depends on a single package and also conflicts with the same package:
$ solve_project << EOF
> (lang dune 3.11)
> (package
> (name foo)
> (allow_empty)
> (depends bar)
> (conflicts bar))
> EOF
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
Selected candidates: foo.dev
- bar -> (problem)
No usable implementations:
bar.0.0.1: Package does not satisfy constraints of local package foo
[1]
Now add an additional conflict on a non-existant package "baz". Dune should continue to fail to find a solution due to the conflict with "bar".
$ solve_project << EOF
> (lang dune 3.11)
> (package
> (name foo)
> (allow_empty)
> (depends bar)
> (conflicts bar baz))
> EOF
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
Selected candidates: foo.dev
- bar -> (problem)
No usable implementations:
bar.0.0.1: Package does not satisfy constraints of local package foo
[1]

View file

@ -0,0 +1,36 @@
Things should be the same whether dependencies are specified or not.
$ . ./helpers.sh
$ make_lockdir
If we have a package we depend on
$ mkdir dependency-source
$ cat >dune.lock/dependency.pkg <<EOF
> (version 0.0.1)
> (source (copy $PWD/dependency-source))
> EOF
And we have a package we want to build
$ mkdir test-source
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (source (copy $PWD/test-source))
> (build
> (system "command -v cat > /dev/null 2>&1 || echo no cat"))
> EOF
$ build_pkg test
Now it fails since adding the dependency modified PATH.
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (source (copy $PWD/test-source))
> ; adding deps breaks cat
> (depends dependency)
> (build
> (system "command -v cat > /dev/null 2>&1 || echo no cat"))
> EOF
$ build_pkg test

View file

@ -0,0 +1,128 @@
We want to make sure our OPAM-repository in git support works well.
$ . ../git-helpers.sh
$ . ./helpers.sh
$ mkrepo
$ mkpkg foo 1.0 <<EOF
> EOF
$ cd mock-opam-repository
$ git init --quiet
$ git add -A
$ git commit --quiet -m "foo 1.0"
$ cd ..
We'll set up a project that uses (only this) this repository, so doesn't use
:standard:
$ add_mock_repo_if_needed "git+file://$PWD/mock-opam-repository"
We depend on the foo package
$ cat > dune-project <<EOF
> (lang dune 3.10)
>
> (package
> (name bar)
> (depends foo))
> EOF
Locking should produce the newest package from the repo
$ mkdir dune-cache
$ XDG_CACHE_HOME=$PWD/dune-cache dune pkg lock
Solution for dune.lock:
- foo.1.0
Now let's assume a new version of foo is released.
$ mkpkg foo 1.1 <<EOF
> EOF
$ cd mock-opam-repository
$ git add -A
$ git commit --quiet -m "foo 1.1 -> new version"
$ cd ..
Locking should update the git repo in our cache folder and give us the newer
version in the lock file
$ XDG_CACHE_HOME=$PWD/dune-cache dune pkg lock
Solution for dune.lock:
- foo.1.1
If the package selected has some additional files that are supposed to be
included for building, these should also be part of the lockfile.
So if we create an extra-file (in OPAM parlance) and attach it to foo.1.2 it
should also be included.
$ FILES_NAME=hello.txt
$ cat > $FILES_NAME <<EOF
> Hello World
> EOF
$ FILES_CHECKSUM=e59ff97941044f85df5297e1c302d260
$ mkpkg foo 1.2 <<EOF
> EOF
$ echo "extra-files: [\"$FILES_NAME\" \"md5=$FILES_CHECKSUM\"]" >> mock-opam-repository/packages/foo/foo.1.2/opam
$ FILES_FOLDER=mock-opam-repository/packages/foo/foo.1.2/files/
$ mkdir -p "$FILES_FOLDER"
$ mv "$FILES_NAME" "$FILES_FOLDER/$FILES_NAME"
$ cd mock-opam-repository
$ git add -A
$ git commit --quiet -m "foo 1.2 with files"
$ cd ..
Locking should be successful and it should include the additional file
$ XDG_CACHE_HOME=$PWD/dune-cache dune pkg lock
Solution for dune.lock:
- foo.1.2
$ find dune.lock | sort
dune.lock
dune.lock/foo.files
dune.lock/foo.files/hello.txt
dune.lock/foo.pkg
dune.lock/lock.dune
The extra-file should have the same content as the original file, we determine
that by hashing with the checksum that we expected in the OPAM file
$ cmp -s dune.lock/foo.files/$FILES_NAME "$FILES_FOLDER/$FILES_NAME" && echo "The contents match"
The contents match
The git repos support repo should also be able to handle unusual objects in our
tree, which can e.g. happen with submodules.
$ cd mock-opam-repository
$ PARENT=$(git rev-parse HEAD)
To make this a bit easier we use some git plumbing commands to reproduce it.
First we create a commit object in the index and write a tree containing this
commit (pointing to nowhere):
$ git update-index --add --cacheinfo 160000,0000000000000000000000000000000000000001,dangling-commit-in-tree
$ TREE=$(git write-tree)
Then we create a commit with the tree and our HEAD as a parent commit
$ CURRENT=$(echo "Added a dangling commit object" | git commit-tree $TREE -p $PARENT)
Then we make this new commit the one that our branch is pointing to.
$ git reset --hard -q $CURRENT
Thus ls-tree should now also contain a commit object:
$ git ls-tree -r HEAD | awk '{ printf "%s %s\n",$2,$4; }' | sort
blob packages/foo/foo.1.0/opam
blob packages/foo/foo.1.1/opam
blob packages/foo/foo.1.2/files/hello.txt
blob packages/foo/foo.1.2/opam
commit dangling-commit-in-tree
$ cd ..
With this set up in place, locking should still work as the commit is not
relevant
$ XDG_CACHE_HOME=$PWD/dune-cache dune pkg lock 2> /dev/null && echo "Solution found"
Solution found

View file

@ -0,0 +1,25 @@
Test fetching from git
$ . ../git-helpers.sh
$ . ./helpers.sh
$ mkdir somerepo
$ cd somerepo
$ git init --quiet
$ echo "hello world" > foo
$ git add foo
$ git commit -am _ --quiet
$ cd ..
$ MYGITREPO=$PWD/somerepo
$ mkdir foo && cd foo
$ make_lockdir
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (source (fetch (url "git+file://$MYGITREPO")))
> (build (run cat foo))
> EOF
$ build_pkg test
hello world

View file

@ -0,0 +1,62 @@
$ . ../git-helpers.sh
$ . ./helpers.sh
When we fetch a package source we should also fetch any submodules. Since we
will use the file protocol for git submodules we will need to explicitly enable
it as it is disabled for security purposes.
$ export GIT_ALLOW_PROTOCOL=file
This repository will be a submodule in our main repository.
$ mkdir someotherrepo
$ cd someotherrepo
$ git init --quiet
$ echo "world" > bar
$ git add bar
$ git commit -am _ --quiet
$ cd ..
$ SOMEOTHERREPO=$PWD/someotherrepo
We create a repository for the package that we wish to build that has
someotherrepo as a submodule.
$ mkdir somerepo
$ cd somerepo
$ git init --quiet
$ echo "hello" > foo
$ git submodule add --quiet $SOMEOTHERREPO mysubmodule
$ git add foo mysubmodule .gitmodules
$ git commit -am _ --quiet
$ cd ..
$ SOMEREPO=$PWD/somerepo
$ mkdir foo && cd foo
$ make_lockdir
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (source (fetch (url "git+file://$SOMEREPO")))
> (build (progn (run cat foo) (run cat mysubmodule/bar)))
> EOF
Building this package should pull in both repositories. At the moment this is
not the case and only somerepo is pulled.
$ build_pkg test 2>&1 | sed -E 's|.*/cat|cat|'
hello
world
When the above works it should act like:
$ make_lockdir
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (source (fetch (url "git+file://$SOMEREPO")))
> (build
> (progn
> (run cp -r $SOMEOTHERREPO/bar mysubmodule)
> (run cat foo)
> (run cat mysubmodule/bar)))
> EOF
$ build_pkg test
hello
world

View file

@ -0,0 +1,102 @@
Test that dune supports lockfiles with md5, sha256 and sha512 hashes.
$ . ./helpers.sh
$ mkrepo
$ add_mock_repo_if_needed
$ mkpkg with-md5 <<EOF
> url {
> src: "file://with-md5"
> checksum: [
> "md5=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
> ]
> }
> EOF
$ mkpkg with-sha256 <<EOF
> url {
> src: "file://with-sha256"
> checksum: [
> "sha256=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
> ]
> }
> EOF
$ mkpkg with-sha512 <<EOF
> url {
> src: "file://with-sha512"
> checksum: [
> "sha512=cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
> ]
> }
> EOF
This package uses multiple hashing algorithms. Currently dune will just add the
first checksum to the lockfile for this package.
$ mkpkg with-all <<EOF
> url {
> src: "file://with-all"
> checksum: [
> "md5=dddddddddddddddddddddddddddddddd"
> "sha256=eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
> "sha512=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
> ]
> }
> extra-source "fixes.patch" {
> src: "https://unimportant.url/unused.patch"
> checksum: [
> "md5=00000000000000000000000000000000"
> "sha256=1111111111111111111111111111111111111111111111111111111111111111"
> "sha512=22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222"
> ]
> }
> EOF
$ solve with-md5 with-sha256 with-sha512 with-all
Solution for dune.lock:
- with-all.0.0.1
- with-md5.0.0.1
- with-sha256.0.0.1
- with-sha512.0.0.1
$ cat dune.lock/*
(lang package 0.1)
(dependency_hash 32180cf311133b30d0b5be2a40c89f43)
(repositories
(complete false)
(used))
(version 0.0.1)
(source
(fetch
(url file://with-all)
(checksum md5=dddddddddddddddddddddddddddddddd)))
(extra_sources
(fixes.patch
(fetch
(url https://unimportant.url/unused.patch)
(checksum md5=00000000000000000000000000000000))))
(version 0.0.1)
(source
(fetch
(url file://with-md5)
(checksum md5=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)))
(version 0.0.1)
(source
(fetch
(url file://with-sha256)
(checksum
sha256=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb)))
(version 0.0.1)
(source
(fetch
(url file://with-sha512)
(checksum
sha512=cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)))

View file

@ -0,0 +1,131 @@
export XDG_CACHE_HOME="$PWD/.cache"
# Set the default platform for the purposes of solving dependencies so that the
# output of tests is platform-independent.
export DUNE_CONFIG__OS=linux
export DUNE_CONFIG__ARCH=x86_64
export DUNE_CONFIG__OS_FAMILY=debian
export DUNE_CONFIG__OS_DISTRIBUTION=ubuntu
export DUNE_CONFIG__OS_VERSION=24.11
export DUNE_CONFIG__SYS_OCAML_VERSION=5.4.0+fake
dune="dune"
pkg_root="_build/_private/default/.pkg"
build_pkg() {
$dune build $pkg_root/$1/target/
}
show_pkg() {
find $pkg_root/$1 | sort | sed "s#$pkg_root/$1##"
}
strip_sandbox() {
sed -E 's#[^ ]*.sandbox/[^/]+#$SANDBOX#g'
}
show_pkg_targets() {
find $pkg_root/$1/target | sort | sed "s#$pkg_root/$1/target##"
}
show_pkg_cookie() {
$dune internal dump $pkg_root/$1/target/cookie
}
mock_packages="mock-opam-repository/packages"
mkrepo() {
mkdir -p $mock_packages
}
mkpkg() {
name=$1
if [ "$#" -eq "1" ]
then
version="0.0.1"
else
version="$2"
fi
mkdir -p $mock_packages/$name/$name.$version
echo 'opam-version: "2.0"' > $mock_packages/$name/$name.$version/opam
cat >>$mock_packages/$name/$name.$version/opam
}
add_mock_repo_if_needed() {
# default, but can be overridden, e.g. if git is required
repo="${1:-file://$(pwd)/mock-opam-repository}"
if [ ! -e dune-workspace ]
then
cat >dune-workspace <<EOF
(lang dune 3.10)
(lock_dir
(repositories mock))
(repository
(name mock)
(url "${repo}"))
EOF
else
if ! grep '(name mock)' > /dev/null dune-workspace
then
# add the repo definition
cat >>dune-workspace <<EOF
(repository
(name mock)
(url "${repo}"))
EOF
# reference the repo
if grep -s '(repositories'
then
sed -i '' -e 's/(repositories \(.*\))/(repositories mock \1)/' dune-workspace
else
cat >>dune-workspace <<EOF
(lock_dir
(repositories mock))
EOF
fi
fi
fi
}
make_lockpkg() {
local dir="dune.lock"
mkdir -p $dir
local f="$dir/$1.pkg"
cat >$f
}
solve_project() {
cat >dune-project
add_mock_repo_if_needed
dune pkg lock $@
}
make_lockdir() {
mkdir -p dune.lock
cat >dune.lock/lock.dune <<EOF
(lang package 0.1)
(repositories (complete true))
EOF
}
make_project() {
cat <<EOF
(lang dune 3.11)
(package
(name x)
(allow_empty)
(depends $@))
EOF
}
print_source() {
cat dune.lock/$1.pkg | sed -n "/source/,//p" | sed "s#$PWD#PWD#g" | tr '\n' ' '| tr -s " "
}
solve() {
make_project $@ | solve_project
}

View file

@ -0,0 +1,22 @@
When building a project with -p we should ignore the lock directory. This is so
that packages with lockdirs in their source archive can be built by opam
without using locked dependencies.
$ . ./helpers.sh
$ make_lockdir
$ cat >dune.lock/test.pkg <<EOF
> (build
> (run echo "I have not been ignored."))
> EOF
$ cat > dune-project <<EOF
> (lang dune 3.11)
> (package
> (name foo)
> (allow_empty)
> (depends test))
> EOF
$ dune build @install -p foo

View file

@ -0,0 +1,56 @@
Test that shows what happens when dune.lock is ignored.
$ . ./helpers.sh
$ make_lockdir
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (build
> (progn
> (run touch foo.ml)
> (patch foo.patch)))
> EOF
$ mkdir dune.lock/test.files
$ cat > dune.lock/test.files/foo.patch <<EOF
> diff --git a/foo.ml b/foo.ml
> index b69a69a5a..ea988f6bd 100644
> --- a/foo.ml
> +++ b/foo.ml
> @@ -0,0 +1 @@
> +let () = print_endline "Hello, World!"
> EOF
$ mkdir src
$ cat > src/dune <<EOF
> (executable
> (name foo))
> EOF
$ cat > src/foo.ml <<EOF
> let () = ()
> EOF
> cat > dune-project <<EOF
> (lang dune 3.16)
> EOF
Building test works when the dune.lock is visible to dune.
$ build_pkg test
Now the project is changed to only include src (which effectively ignores
dune.lock):
$ cat > dune <<EOF
> (dirs src)
> EOF
Building fails as the patch cannot be found anymore
$ build_pkg test 2>&1 | sed 's|\.sandbox/[a-f0-9]*/|.sandbox/<hash>/|'
Error:
open(_build/.sandbox/<hash>/_private/default/.pkg/test/source/foo.patch): No such file or directory
-> required by _build/_private/default/.pkg/test/target
And the backage cannot be shown:
$ show_pkg test

View file

@ -0,0 +1,42 @@
By default, we introduce a constraint on in the build plan that will require
the dune version to match the version of dune being used to generate the
constraint. On another hand, we ensure `dune` can be used as a declared
dependency.
$ . ./helpers.sh
$ mkrepo
$ mkpkg dune 3.11.0 <<EOF
> EOF
$ test() {
> mkpkg foo <<EOF
> depends: [ "dune" {<= "$1"} ]
> EOF
> solve foo
> }
$ test "2.0.0" 2>&1 | sed -E 's/3.[0-9]+/3.XX/g'
Error: Unable to solve dependencies for the following lock directories:
Lock directory dune.lock:
Couldn't solve the package dependency formula.
Selected candidates: foo.0.0.1 x.dev
- dune -> (problem)
User requested = 3.XX
Rejected candidates:
dune.3.XX.0: Incompatible with restriction: = 3.XX
$ test "4.0.0"
Solution for dune.lock:
- foo.0.0.1
Create a fake project and ensure `dune` can be used as a dependency:
$ cat > dune-project <<EOF
> (lang dune 3.13)
> (package
> (name bar)
> (allow_empty)
> (depends dune))
> EOF
$ dune pkg lock
Solution for dune.lock:
(no dependencies to lock)

View file

@ -0,0 +1,25 @@
Install actions should have the switch directory prepared:
$ . ./helpers.sh
$ make_lockdir
$ cat >dune.lock/test.pkg <<'EOF'
> (version 0.0.1)
> (install (system "find %{prefix} | sort"))
> EOF
$ build_pkg test
../target
../target/bin
../target/doc
../target/doc/test
../target/etc
../target/etc/test
../target/lib
../target/lib/stublibs
../target/lib/test
../target/lib/toplevel
../target/man
../target/sbin
../target/share
../target/share/test

View file

@ -0,0 +1,41 @@
Testing install actions
$ . ./helpers.sh
$ make_lockdir
$ cat >dune.lock/test.pkg <<'EOF'
> (version 0.0.1)
> (install (system "echo foobar; mkdir -p %{lib}; touch %{lib}/xxx"))
> EOF
$ build_pkg test
foobar
$ export BUILD_PATH_PREFIX_MAP="/PKG_ROOT=test/target:$BUILD_PATH_PREFIX_MAP"
$ show_pkg_targets test
/bin
/cookie
/doc
/doc/test
/etc
/etc/test
/lib
/lib/stublibs
/lib/test
/lib/toplevel
/lib/xxx
/man
/sbin
/share
/share/test
$ show_pkg_cookie test
{ files =
map
{ LIB_ROOT :
[ In_build_dir "_private/default/.pkg/test/target/lib/xxx" ]
}
; variables = []
}

View file

@ -0,0 +1,16 @@
Use build paths in the install entries of a package
$ . ./helpers.sh
$ make_lockdir
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (build
> (system "\| cat >test.install <<EOF
> "\| bin: [ "?_build/install/default/bin/foo" ]
> "\| EOF
> ))
> EOF
$ build_pkg test

View file

@ -0,0 +1,28 @@
Test missing entries in the .install file
$ . ./helpers.sh
$ make_lockdir
$ lockfile() {
> cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (build
> (system "echo 'lib: [ \"$1\" ]' > test.install"))
> EOF
> }
This should give us a proper error that myfile wasn't generated
$ lockfile "myfile"
$ build_pkg test 2>&1 | sed 's#_build.*_private#$ROOT/_private#'
Error: entry
$ROOT/_private/default/.pkg/test/source/myfile
in
$ROOT/_private/default/.pkg/test/source/test.install
does not exist
-> required by $ROOT/_private/default/.pkg/test/target
This on the other hand shouldn't error because myfile is optional
$ lockfile "?myfile"
$ build_pkg test

View file

@ -0,0 +1,74 @@
Test that installed binaries are visible in dependent packages
$ . ./helpers.sh
$ make_lockdir
$ cat >dune.lock/test.pkg <<EOF
> (version 0.0.1)
> (build
> (system "\| echo "#!/bin/sh\necho from test package" > foo;
> "\| chmod +x foo;
> "\| touch libxxx lib_rootxxx;
> "\| cat >test.install <<EOF
> "\| bin: [ "foo" ]
> "\| lib: [ "libxxx" ]
> "\| lib_root: [ "lib_rootxxx" ]
> "\| share_root: [ "lib_rootxxx" ]
> "\| EOF
> ))
> EOF
$ cat >dune.lock/usetest.pkg <<EOF
> (version 0.0.1)
> (depends test)
> (build
> (progn
> (run foo)
> (run mkdir -p %{prefix})))
> EOF
$ build_pkg usetest
from test package
$ show_pkg_targets test
/bin
/bin/foo
/cookie
/lib
/lib/lib_rootxxx
/lib/test
/lib/test/libxxx
/share
/share/lib_rootxxx
$ show_pkg_cookie test
{ files =
map
{ LIB :
[ In_build_dir "_private/default/.pkg/test/target/lib/test/libxxx"
]
; LIB_ROOT :
[ In_build_dir "_private/default/.pkg/test/target/lib/lib_rootxxx"
]
; BIN : [ In_build_dir "_private/default/.pkg/test/target/bin/foo" ]
; SHARE_ROOT :
[ In_build_dir
"_private/default/.pkg/test/target/share/lib_rootxxx"
]
}
; variables = []
}
It should also be visible in the workspace:
$ cat >dune-project <<EOF
> (lang dune 3.9)
> EOF
$ cat >dune <<EOF
> (rule
> (with-stdout-to testout (run %{bin:foo})))
> EOF
$ dune build ./testout && cat _build/default/testout
from test package

View file

@ -0,0 +1,49 @@
Test the error cases for invalid opam repositories
$ . ../helpers.sh
$ cat >dune-project <<EOF
> (lang dune 3.8)
> (package
> (name lockfile_generation_test))
> EOF
$ add_mock_repo_if_needed "file://$(pwd)/directory-that-does-not-exist"
$ lock() {
> out="$(dune pkg lock 2>&1)"
> local code="$?"
> echo "$out" | sed 's/character.*:/characters X-X:/g' \
> | sed 's/url ".*"/url ../g' \
> | grep -v "\^"
> return $code
> }
$ lock
File "dune-workspace", line 6, characters X-X:
6 | (url ..))
Error:
$TESTCASE_ROOT/directory-that-does-not-exist
does not exist
[1]
$ touch empty
$ rm dune-workspace
$ add_mock_repo_if_needed "file://$(pwd)/empty"
$ lock
File "dune-workspace", line 6, characters X-X:
6 | (url ..))
Error:
$TESTCASE_ROOT/empty
is not a directory
[1]
$ rm dune-workspace
$ add_mock_repo_if_needed "file://$(pwd)/no-packages-dir"
$ lock
File "dune-workspace", line 6, characters X-X:
6 | (url ..))
Error:
$TESTCASE_ROOT/no-packages-dir
doesn't look like a path to an opam repository as it lacks a subdirectory
named "packages"
[1]

View file

@ -0,0 +1,25 @@
Having an invalid package dependency that looks like an opam-versioned package
gives a good user message rather. It is very likely that users will type
foo.1.2.3 for a package version due to the convention in opam.
In this case we could also hint at the correct syntax for dune-project files.
$ . ./helpers.sh
$ mkrepo
$ mkpkg foo 1.2.3
$ cat > dune-project <<EOF
> (lang dune 3.13)
> (package
> (name invalid)
> (depends foo.1.2.3))
> EOF
$ add_mock_repo_if_needed
$ dune pkg lock 2>&1
File "dune-project", line 4, characters 10-19:
4 | (depends foo.1.2.3))
^^^^^^^^^
Error: "foo.1.2.3" is an invalid package dependency.
Package names can contain letters, numbers, '-', '_' and '+', and need to
contain at least a letter.
Hint: (foo (= 1.2.3)) would be a correct package dependency
[1]

View file

@ -0,0 +1,67 @@
Add some build contexts with different environments
$ cat >dune-workspace <<EOF
> (lang dune 3.8)
> (lock_dir
> (path dune.lock)
> (unset_solver_vars arch os-distribution os os-family os-version sys-ocaml-version))
> (lock_dir
> (path dune.linux.lock)
> (solver_env
> (os linux))
> (unset_solver_vars arch os-distribution os-family os-version sys-ocaml-version))
> (lock_dir
> (path dune.linux.no-doc.lock)
> (solver_env
> (arch x86_64)
> (os linux)
> (os-family ubuntu)
> (os-distribution ubuntu)
> (os-version 22.04)
> (sys-ocaml-version 5.0)))
> (lock_dir
> (path change-opam-version.lock)
> (solver_env
> (opam-version 42))
> (unset_solver_vars arch os os-distribution os-family os-version sys-ocaml-version))
> (context
> (default
> (name linux)
> (lock_dir dune.linux.lock)))
> (context
> (default
> (name no-doc)
> (lock_dir dune.linux.no-doc.lock)))
> (context
> (default
> (name change-opam-version)
> (lock_dir change-opam-version.lock)))
> EOF
$ dune pkg print-solver-env --all
Solver environment for lock directory change-opam-version.lock:
- opam-version = 42
- post = true
- with-dev-setup = false
- with-doc = false
Solver environment for lock directory dune.linux.lock:
- opam-version = 2.2.0~alpha-vendored
- os = linux
- post = true
- with-dev-setup = false
- with-doc = false
Solver environment for lock directory dune.linux.no-doc.lock:
- arch = x86_64
- opam-version = 2.2.0~alpha-vendored
- os = linux
- os-distribution = ubuntu
- os-family = ubuntu
- os-version = 22.04
- post = true
- sys-ocaml-version = 5.0
- with-dev-setup = false
- with-doc = false
Solver environment for lock directory dune.lock:
- opam-version = 2.2.0~alpha-vendored
- post = true
- with-dev-setup = false
- with-doc = false

View file

@ -0,0 +1,50 @@
This test attempts to build a library installed through a lock file and then
use it inside dune.
$ . ./helpers.sh
We set up a library that will be installed as part of the package:
$ mkdir external_sources
$ cat >external_sources/dune-project <<EOF
> (lang dune 3.11)
> (package (name mypkg))
> EOF
$ cat >external_sources/dune <<EOF
> (library
> (public_name mypkg.lib)
> (name test_lib))
> EOF
$ cat >external_sources/test_lib.ml <<EOF
> let x = ()
> EOF
Now we set up a lock file with this package and then attempt to use it:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> EOF
$ mkdir dune.lock
$ cat >dune.lock/lock.dune <<EOF
> (lang package 0.1)
> EOF
$ cat >dune.lock/mypkg.pkg <<EOF
> (version 0.0.1)
> (source (copy $PWD/external_sources))
> (build (run dune build --release --promote-install-file=true . @install))
> EOF
$ cat >dune <<EOF
> (dirs (:standard \ external_sources))
> (library
> (name foo)
> (libraries mypkg.lib))
> EOF
$ cat >foo.ml <<EOF
> let () = Test_lib.x
> EOF
$ dune build foo.cma

View file

@ -0,0 +1,26 @@
Dune is defined in the workspace where we're solving
$ . ./helpers.sh
$ mkrepo
$ mkpkg bar <<EOF
> depends: [ "dune" ]
> EOF
$ mkpkg test-dep <<EOF
> depends: [ "dune" ]
> EOF
$ solve_project <<EOF
> (lang dune 3.19)
> (package
> (name dune)
> (depends (test-dep :with-test)))
> (package
> (name foo)
> (depends bar))
> EOF
Solution for dune.lock:
- bar.0.0.1
- test-dep.0.0.1

View file

@ -0,0 +1,63 @@
Create a lock directory that didn't originally exist
$ cat >dune-workspace <<EOF
> (lang dune 3.10)
> (lock_dir
> (repositories mock))
> (lock_dir
> (path "dev/dune.lock")
> (repositories mock))
> (repository
> (name mock)
> (url "file://$(pwd)/mock-opam-repository"))
> EOF
$ dune pkg lock "dev/dune.lock"
Solution for dev/dune.lock:
(no dependencies to lock)
$ dune pkg lock
Solution for dune.lock:
(no dependencies to lock)
$ cat dune.lock/lock.dune
(lang package 0.1)
(repositories
(complete false)
(used))
Re-create a lock directory in the newly created lock dir
$ dune pkg lock
Solution for dune.lock:
(no dependencies to lock)
$ cat dune.lock/lock.dune
(lang package 0.1)
(repositories
(complete false)
(used))
Attempt to create a lock directory inside an existing directory without a lock.dune file
$ rm -rf dune.lock
$ cp -r dir-without-metadata dune.lock
$ dune pkg lock
Error: Refusing to regenerate lock directory dune.lock
Specified lock dir lacks metadata file (lock.dune)
[1]
Attempt to create a lock directory inside an existing directory with an invalid lock.dune file
$ rm -rf dune.lock
$ cp -r dir-with-invalid-metadata dune.lock
$ dune pkg lock
Error: Refusing to regenerate lock directory dune.lock
Unable to parse lock directory metadata file (dune.lock/lock.dune):
File "dune.lock/lock.dune", line 1, characters 0-12:
Error: Invalid first line, expected: (lang <lang> <version>)
[1]
Attempt to create a lock directory with the same name as an existing regular file
$ rm -rf dune.lock
$ touch dune.lock
$ dune pkg lock
Error: Refusing to regenerate lock directory dune.lock
Specified lock dir path (dune.lock) is not a directory
[1]

View file

@ -0,0 +1,142 @@
Test that dune can dynamically select a lockdir with a cond statement
$ . ./helpers.sh
$ mkrepo
$ mkpkg arm64-only <<EOF
> install: [ "echo" "arm64-only" ]
> EOF
$ mkpkg linux-only <<EOF
> install: [ "echo" "linux-only" ]
> EOF
$ mkpkg macos-only <<EOF
> install: [ "echo" "macos-only" ]
> EOF
$ cat >dune-workspace <<EOF
> (lang dune 3.13)
> (lock_dir
> (path dune.macos.arm64.lock)
> (repositories mock)
> (solver_env
> (arch arm64)
> (os macos)))
> (lock_dir
> (path dune.macos.lock)
> (repositories mock)
> (solver_env
> (arch amd64)
> (os macos)))
> (lock_dir
> (path dune.linux.lock)
> (repositories mock)
> (solver_env
> (arch amd64)
> (os linux)))
> (lock_dir
> (repositories mock))
> (repository
> (name mock)
> (url "file://$(pwd)/mock-opam-repository"))
> (context
> (default
> (lock_dir (cond
> ((and
> (= %{architecture} arm64)
> (= %{system} macosx)) dune.macos.arm64.lock)
> ((= %{system} macosx) dune.macos.lock)
> ((= %{system} linux) dune.linux.lock)))))
> EOF
$ cat > dune-project <<EOF
> (lang dune 3.13)
> (package
> (name foo)
> (depends
> (arm64-only (= :arch arm64))
> (macos-only (= :os macos))
> (linux-only (= :os linux))))
> EOF
Generate all lockdirs:
$ dune pkg lock dune.macos.arm64.lock
Solution for dune.macos.arm64.lock:
- arm64-only.0.0.1
- macos-only.0.0.1
$ dune pkg lock dune.macos.lock
Solution for dune.macos.lock:
- macos-only.0.0.1
$ dune pkg lock dune.linux.lock
Solution for dune.linux.lock:
- linux-only.0.0.1
Demonstrate that the correct lockdir is being chosen by building packages that
are only dependent on on certain systems.
Build macos package on macos:
$ dune clean
$ DUNE_CONFIG__OS=macos DUNE_CONFIG__ARCH=arm64 dune build _build/_private/default/.pkg/macos-only/target/
macos-only
Build macos package on macos:
$ dune clean
$ DUNE_CONFIG__OS=macos DUNE_CONFIG__ARCH=amd64 dune build _build/_private/default/.pkg/macos-only/target/
macos-only
Build linux package on macos (will fail):
$ dune clean
$ DUNE_CONFIG__OS=macos DUNE_CONFIG__ARCH=amd64 dune build _build/_private/default/.pkg/linux-only/target/
Error: Unknown package "linux-only"
[1]
Build macos package on linux (will fail):
$ dune clean
$ DUNE_CONFIG__OS=linux DUNE_CONFIG__ARCH=amd64 dune build _build/_private/default/.pkg/macos-only/target/
Error: Unknown package "macos-only"
[1]
Build linux package on linux:
$ dune clean
$ DUNE_CONFIG__OS=linux DUNE_CONFIG__ARCH=amd64 dune build _build/_private/default/.pkg/linux-only/target/
linux-only
Try setting the os to one which doesn't have a corresponding lockdir:
$ dune clean
$ DUNE_CONFIG__OS=windows dune build _build/_private/default/.pkg/linux-only/target/
File "dune-workspace", lines 28-32, characters 3-172:
28 | ((and
29 | (= %{architecture} arm64)
30 | (= %{system} macosx)) dune.macos.arm64.lock)
31 | ((= %{system} macosx) dune.macos.lock)
32 | ((= %{system} linux) dune.linux.lock)))))
Error: None of the conditions matched so no lockdir could be chosen.
[1]
Test that cond statements can have a default value:
$ cat >dune-workspace <<EOF
> (lang dune 3.13)
> (lock_dir
> (solver_env
> (arch amd64)
> (os linux))
> (repositories mock))
> (repository
> (name mock)
> (url "file://$(pwd)/mock-opam-repository"))
> (context
> (default
> (lock_dir
> (cond
> (false non-existant)
> (default dune.lock)))))
> EOF
$ dune pkg lock dune.lock
Solution for dune.lock:
- linux-only.0.0.1
$ dune clean
$ dune build _build/_private/default/.pkg/linux-only/target/
linux-only

View file

@ -0,0 +1,56 @@
Trying to build a package after updating the dependencies in dune-project but
without running `dune pkg lock` must raise an error in the context of Dune
Package Managemenet.
$ . ./helpers.sh
Create a fake project and lock it:
$ mkrepo
$ mkpkg foo <<EOF
> build: [ "echo" "foo" ]
> EOF
$ mkpkg bar <<EOF
> build: [ "echo" "bar" ]
> EOF
$ cat > dune-project <<EOF
> (lang dune 3.16)
> (package
> (name test)
> (allow_empty)
> (depends foo))
> EOF
$ add_mock_repo_if_needed
$ dune pkg lock
Solution for dune.lock:
- foo.0.0.1
As the lock file is syncronised with `dune-pkg`, the build succeeds:
$ build_pkg foo
foo
We add the bar dependency to the test package
$ cat > dune-project <<EOF
> (lang dune 3.16)
> (package
> (name test)
> (allow_empty)
> (depends foo bar))
> EOF
It fails as we have not regenerated the lock:
$ dune build
File "dune.lock/lock.dune", line 1, characters 0-0:
Error: The lock dir is not sync with your dune-project
Hint: run dune pkg lock
[1]
We fix it and the build succeeds again:
$ dune pkg lock
Solution for dune.lock:
- bar.0.0.1
- foo.0.0.1
$ build_pkg foo
$ build_pkg bar
bar

View file

@ -0,0 +1,189 @@
Tests that dune can detect when the lockdir has diverged from the local package
dependencies due to tampering with the lockdir. These are cases that won't be
caught by checking the dependency hash.
$ . ./helpers.sh
$ mkrepo
$ mkpkg a <<EOF
> depends: [ "c" "d" ]
> EOF
$ mkpkg b 0.0.1 <<EOF
> EOF
$ mkpkg b 0.0.2 <<EOF
> EOF
$ mkpkg c <<EOF
> depends: [ "e" ]
> EOF
$ mkpkg d <<EOF
> EOF
$ mkpkg e <<EOF
> EOF
Define some local packages.
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package (name foo) (depends a (b (>= 0.0.2))))
> (package (name bar) (depends foo c))
> EOF
$ add_mock_repo_if_needed
Without a lockdir this command prints a hint but exits successfully.
$ dune pkg validate-lockdir
No lockdirs to validate.
Make the lockdir.
$ dune pkg lock
Solution for dune.lock:
- a.0.0.1
- b.0.0.2
- c.0.0.1
- d.0.0.1
- e.0.0.1
Initially the lockdir will be valid.
$ dune pkg validate-lockdir
Add a file to the lockdir to cause the parser to fail.
$ echo foo > dune.lock/bar.pkg
$ dune pkg validate-lockdir
Failed to parse lockdir dune.lock:
File "dune.lock/bar.pkg", line 1, characters 0-3:
Error: S-expression of the form (<name> <values>...) expected
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Remove the file but corrupt the lockdir metadata file.
$ rm dune.lock/bar.pkg
$ echo foo >> dune.lock/lock.dune
$ dune pkg validate-lockdir
Failed to parse lockdir dune.lock:
File "dune.lock/lock.dune", line 8, characters 0-3:
Error: S-expression of the form (<name> <values>...) expected
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Regenerate the lockdir and validate the result.
$ rm -r dune.lock
$ dune pkg lock
Solution for dune.lock:
- a.0.0.1
- b.0.0.2
- c.0.0.1
- d.0.0.1
- e.0.0.1
$ dune pkg validate-lockdir
Remove a package from the lockdir.
$ rm dune.lock/a.pkg
This results in an invalid lockdir due to the missing package.
$ dune pkg validate-lockdir
Lockdir dune.lock does not contain a solution for local packages:
File "dune-project", line 2, characters 0-47:
Error: The dependencies of local package "foo" could not be satisfied from
the lockdir:
Package "a" is missing
Hint: The lockdir no longer contains a solution for the local packages in
this project. Regenerate the lockdir by running: 'dune pkg lock'
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Regenerate the lockdir and validate the result.
$ dune pkg lock
Solution for dune.lock:
- a.0.0.1
- b.0.0.2
- c.0.0.1
- d.0.0.1
- e.0.0.1
$ dune pkg validate-lockdir
$ cat dune.lock/b.pkg
(version 0.0.2)
Change the version of a dependency by modifying its lockfile.
$ cat >dune.lock/b.pkg <<EOF
> (version 0.0.1)
> EOF
Now the lockdir is invalid as it doesn't contain the right version of "b".
$ dune pkg validate-lockdir
Lockdir dune.lock does not contain a solution for local packages:
File "dune-project", line 2, characters 0-47:
Error: The dependencies of local package "foo" could not be satisfied from
the lockdir:
Found version "0.0.1" of package "b" which doesn't satisfy the required
version constraint ">= 0.0.2"
Hint: The lockdir no longer contains a solution for the local packages in
this project. Regenerate the lockdir by running: 'dune pkg lock'
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Regenerate the lockdir and validate the result.
$ dune pkg lock
Solution for dune.lock:
- a.0.0.1
- b.0.0.2
- c.0.0.1
- d.0.0.1
- e.0.0.1
$ dune pkg validate-lockdir
Add a package to the lockdir with the same name as a local package.
$ cat >dune.lock/foo.pkg <<EOF
> (version 0.0.1)
> EOF
The lockdir is invalid as the package "b" is now defined both locally and in the lockdir.
$ dune pkg validate-lockdir
Lockdir dune.lock does not contain a solution for local packages:
File "dune-project", line 2, characters 0-47:
Error: A package named "foo" is defined locally but is also present in the
lockdir
Hint: The lockdir no longer contains a solution for the local packages in
this project. Regenerate the lockdir by running: 'dune pkg lock'
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Regenerate the lockdir and validate the result.
$ dune pkg lock
Solution for dune.lock:
- a.0.0.1
- b.0.0.2
- c.0.0.1
- d.0.0.1
- e.0.0.1
$ dune pkg validate-lockdir
Add a package to the lockdir which isn't part of the local package dependency hierarchy.
$ cat >dune.lock/f.pkg <<EOF
> (version 0.0.1)
> EOF
The lockdir is invalid as it contains unnecessary packages.
$ dune pkg validate-lockdir
Lockdir dune.lock does not contain a solution for local packages:
Error: The lockdir contains packages which are not among the transitive
dependencies of any local package:
- f.0.0.1
Hint: The lockdir no longer contains a solution for the local packages in
this project. Regenerate the lockdir by running: 'dune pkg lock'
Error: Some lockdirs do not contain solutions for local packages:
- dune.lock
[1]
Regenerate the lockdir and validate the result.
$ dune pkg lock
Solution for dune.lock:
- a.0.0.1
- b.0.0.2
- c.0.0.1
- d.0.0.1
- e.0.0.1
$ dune pkg validate-lockdir

View file

@ -0,0 +1,56 @@
Check that if the user tampers with the lockdir in a way that invalidates the
package graph then it's caught when loading the lockdir.
$ . ./helpers.sh
$ make_lockdir
$ cat >dune.lock/a.pkg <<EOF
> (version 0.0.1)
> (depends b)
> EOF
$ cat >dune.lock/b.pkg <<EOF
> (version 0.0.1)
> (depends c)
> EOF
$ cat >dune.lock/c.pkg <<EOF
> (version 0.0.1)
> (depends a)
> EOF
$ dune describe pkg lock
Contents of dune.lock:
- a.0.0.1
- b.0.0.1
- c.0.0.1
$ cat >dune.lock/c.pkg <<EOF
> (version 0.0.1)
> (depends a d)
> EOF
$ dune describe pkg lock
File "dune.lock/c.pkg", line 2, characters 11-12:
The package "c" depends on the package "d", but "d" does not appear in the
lockdir dune.lock.
Error: At least one package dependency is itself not present as a package in
the lockdir dune.lock.
Hint: This could indicate that the lockdir is corrupted. Delete it and then
regenerate it by running: 'dune pkg lock'
[1]
$ rm dune.lock/a.pkg
$ dune describe pkg lock
File "dune.lock/c.pkg", line 2, characters 9-10:
The package "c" depends on the package "a", but "a" does not appear in the
lockdir dune.lock.
File "dune.lock/c.pkg", line 2, characters 11-12:
The package "c" depends on the package "d", but "d" does not appear in the
lockdir dune.lock.
Error: At least one package dependency is itself not present as a package in
the lockdir dune.lock.
Hint: This could indicate that the lockdir is corrupted. Delete it and then
regenerate it by running: 'dune pkg lock'
[1]

View file

@ -0,0 +1,45 @@
When populating the "deps" field of a lockfile, only packages which have locked
versions compatible with the lockfile's package's dependency version
constraints should be included.
$ . ./helpers.sh
$ mkrepo
$ mkpkg a 0.0.1
$ mkpkg a 0.0.2
$ mkpkg b
The package "c" can be satisfied by b or by a.0.0.1.
$ mkpkg c <<EOF
> depends: [ "b" | "a" {= "0.0.1"} ]
> EOF
The package "d" can only be satisfied by "a.0.0.2" which will force the package
"c" to depend on "b" rather than "a" and ensure "a.0.0.2" is in the solution
rather than "a.0.0.1".
$ mkpkg d <<EOF
> depends: [ "a" {= "0.0.2"} ]
> EOF
$ solve_project <<EOF
> (lang dune 3.11)
> (package
> (name foo)
> (depends c d))
> EOF
Solution for dune.lock:
- a.0.0.2
- b.0.0.1
- c.0.0.1
- d.0.0.1
Confirm that we locked "a.0.0.2".
$ cat dune.lock/a.pkg
(version 0.0.2)
The deps in the lockfile for "c" shouldn't contain "a" since the only version
of "a" that "c" could depend on is "a.0.0.1" which isn't part of the solution.
$ cat dune.lock/c.pkg
(version 0.0.1)
(depends b)

Some files were not shown because too many files have changed in this diff Show more