Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Pkg v1.13 Release Notes
=======================

- `Pkg.test` now respects the `--check-bounds` setting from the parent Julia session instead of forcing `--check-bounds=yes`.

- Project.toml environments now support a `readonly` field to mark environments as read-only, preventing modifications.
([#4284])
- `Pkg.build` now supports an `allow_reresolve` keyword argument to control whether the build process can re-resolve
Expand Down
12 changes: 10 additions & 2 deletions docs/src/creating-packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,20 +297,28 @@ projects = ["test"]
(HelloWorld) pkg> activate ./test
[ Info: activating environment at `~/HelloWorld/test/Project.toml`.

(HelloWorld/test) pkg> add Test
(HelloWorld/test) pkg> dev . # add current package to test dependencies using its path
Resolving package versions...
Updating `~/HelloWorld/test/Project.toml`
[8dfed614] + HelloWorld v0.1.0 `..`

(HelloWorld/test) pkg> add Test # add other test dependencies
Resolving package versions...
Updating `~/HelloWorld/test/Project.toml`
[8dfed614] + Test
```

When using workspaces, the package manager resolves dependencies for all projects in the workspace together, and creates a single `Manifest.toml` next to the base `Project.toml`. This provides better dependency resolution and makes it easier to manage test-specific dependencies.

!!! warning
Unlike some earlier test dependency workflows, this one explicitly requires adding `HelloWorld` (the parent package) to your `test/Project.toml`.

You can now use `Test` in the test script:

```julia-repl
julia> write("test/runtests.jl",
"""
using Test
using HelloWorld, Test
@test 1 == 1
""");

Expand Down
38 changes: 18 additions & 20 deletions ext/REPLExt/completions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,32 +78,30 @@ function complete_remote_package!(comps, partial; hint::Bool)
name = regpkg.name
name in cmp && continue
if startswith(regpkg.name, partial)
pkg = Registry.registry_info(regpkg)
pkg = Registry.registry_info(reg, regpkg)
Registry.isdeprecated(pkg) && continue
compat_info = Registry.compat_info(pkg)
# Filter versions
for (v, uncompressed_compat) in compat_info
# Check if any non-yanked version is compatible with current Julia
found_compatible_version = false
for v in keys(pkg.version_info)
Registry.isyanked(pkg, v) && continue
# TODO: Filter based on offline mode
is_julia_compat = nothing
for (pkg_uuid, vspec) in uncompressed_compat
if pkg_uuid == JULIA_UUID
is_julia_compat = VERSION in vspec
is_julia_compat && continue
end
end
# Found a compatible version or compat on julia at all => compatible
if is_julia_compat === nothing || is_julia_compat
push!(cmp, name)
# In hint mode the result is only used if there is a single matching entry
# so we can return no matches in case of more than one match
if hint && found_match
return true # true means returned early
end
found_match = true
# Query compressed compat for this version (optimized: only fetch Julia compat)
julia_vspec = Pkg.Registry.query_compat_for_version(pkg, v, JULIA_UUID)
# Found a compatible version or no julia compat at all => compatible
if julia_vspec === nothing || VERSION in julia_vspec
found_compatible_version = true
break
end
end
if found_compatible_version
push!(cmp, name)
# In hint mode the result is only used if there is a single matching entry
# so we can return no matches in case of more than one match
if hint && found_match
return true # true means returned early
end
found_match = true
end
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions src/API.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1346,11 +1346,11 @@ function instantiate(
end
repo_path = Types.add_repo_cache_path(repo_source)
let repo_source = repo_source
LibGit2.with(GitTools.ensure_clone(ctx.io, repo_path, repo_source; isbare = true)) do repo
LibGit2.with(GitTools.ensure_clone(ctx.io, repo_path, repo_source; isbare = true, depth = 1)) do repo
# We only update the clone if the tree hash can't be found
tree_hash_object = tree_hash(repo, string(pkg.tree_hash))
if tree_hash_object === nothing
GitTools.fetch(ctx.io, repo, repo_source; refspecs = Types.refspecs)
GitTools.fetch(ctx.io, repo, repo_source; refspecs = Types.refspecs, depth = LibGit2.Consts.FETCH_DEPTH_UNSHALLOW)
tree_hash_object = tree_hash(repo, string(pkg.tree_hash))
end
if tree_hash_object === nothing
Expand Down
7 changes: 5 additions & 2 deletions src/Apps/Apps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function get_max_version_register(pkg::PackageSpec, regs)
if get(reg, pkg.uuid, nothing) !== nothing
reg_pkg = get(reg, pkg.uuid, nothing)
reg_pkg === nothing && continue
pkg_info = Registry.registry_info(reg_pkg)
pkg_info = Registry.registry_info(reg, reg_pkg)
for (version, info) in pkg_info.version_info
info.yanked && continue
if pkg.version isa VersionNumber
Expand Down Expand Up @@ -216,6 +216,9 @@ function add(pkg::PackageSpec)
manifest.deps[pkg.uuid] = entry

_resolve(manifest, pkg.name)
if new === true || (new isa Set{UUID} && pkg.uuid in new)
Pkg.Operations.build_versions(ctx, Set([pkg.uuid]); verbose = true)
end
precompile(pkg.name)

@info "For package: $(pkg.name) installed apps $(join(keys(project.apps), ","))"
Expand All @@ -231,7 +234,7 @@ end

function develop(pkg::PackageSpec)
if pkg.path !== nothing
pkg.path == abspath(pkg.path)
pkg.path = abspath(pkg.path)
end
handle_package_input!(pkg)
ctx = app_context()
Expand Down
80 changes: 73 additions & 7 deletions src/GitTools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,45 @@ using Printf
use_cli_git() = Base.get_bool_env("JULIA_PKG_USE_CLI_GIT", false)
const RESOLVING_DELTAS_HEADER = "Resolving Deltas:"

# Check if LibGit2 supports shallow clones (requires LibGit2 >= 1.7.0)
# We check both the LibGit2 version and the existence of `isshallow` to ensure
# the shallow clone functionality is available
function supports_shallow_clone()
# This seems buggy on Windows? Get some weird CI errors with it.
if Sys.iswindows()
return false
end
has_version = @static if isdefined(LibGit2, :VERSION)
LibGit2.VERSION >= v"1.7.0"
else
false
end
has_isshallow = isdefined(LibGit2, :isshallow)
return has_version && has_isshallow
end

# Check if a URL is a local path or file:// URL
# Shallow clones are only supported for network protocols (HTTP, HTTPS, Git, SSH)
function is_local_repo(url::AbstractString)
# Check if it's a local filesystem path
ispath(url) && return true
# Check if it uses file:// protocol
startswith(url, "file://") && return true
return false
end

# Check if a repository is a shallow clone
function isshallow(repo::LibGit2.GitRepo)
if supports_shallow_clone() && isdefined(LibGit2, :isshallow)
return LibGit2.isshallow(repo)
else
# Fallback: check for .git/shallow file
repo_path = LibGit2.path(repo)
shallow_file = joinpath(repo_path, "shallow")
return isfile(shallow_file)
end
end

function transfer_progress(progress::Ptr{LibGit2.TransferProgress}, p::Any)
progress = unsafe_load(progress)
@assert haskey(p, :transfer_progress)
Expand Down Expand Up @@ -89,11 +128,17 @@ function checkout_tree_to_path(repo::LibGit2.GitRepo, tree::LibGit2.GitObject, p
end
end

function clone(io::IO, url, source_path; header = nothing, credentials = nothing, isbare = false, kwargs...)
function clone(io::IO, url, source_path; header = nothing, credentials = nothing, isbare = false, depth::Integer = 0, kwargs...)
url = String(url)::String
source_path = String(source_path)::String
@assert !isdir(source_path) || isempty(readdir(source_path))
url = normalize_url(url)

# Disable shallow clones for local repos (not supported) or if LibGit2 doesn't support it
if depth > 0 && (is_local_repo(url) || !supports_shallow_clone())
depth = 0
end

printpkgstyle(io, :Cloning, header === nothing ? "git-repo `$url`" : header)
bar = MiniProgressBar(header = "Cloning:", color = Base.info_color())
fancyprint = can_fancyprint(io)
Expand All @@ -103,8 +148,10 @@ function clone(io::IO, url, source_path; header = nothing, credentials = nothing
end
return try
if use_cli_git()
args = ["--quiet", url, source_path]
isbare && pushfirst!(args, "--bare")
args = ["--quiet"]
depth > 0 && push!(args, "--depth=$depth")
isbare && push!(args, "--bare")
push!(args, url, source_path)
cmd = `git clone $args`
try
run(pipeline(cmd; stdout = devnull))
Expand All @@ -124,7 +171,12 @@ function clone(io::IO, url, source_path; header = nothing, credentials = nothing
LibGit2.Callbacks()
end
mkpath(source_path)
return LibGit2.clone(url, source_path; callbacks, credentials, isbare, kwargs...)
# Only pass depth if shallow clones are supported and depth > 0
if depth > 0
return LibGit2.clone(url, source_path; callbacks, credentials, isbare, depth, kwargs...)
else
return LibGit2.clone(url, source_path; callbacks, credentials, isbare, kwargs...)
end
end
catch err
rm(source_path; force = true, recursive = true)
Expand All @@ -149,10 +201,16 @@ function geturl(repo)
end
end

function fetch(io::IO, repo::LibGit2.GitRepo, remoteurl = nothing; header = nothing, credentials = nothing, refspecs = [""], kwargs...)
function fetch(io::IO, repo::LibGit2.GitRepo, remoteurl = nothing; header = nothing, credentials = nothing, refspecs = [""], depth::Integer = 0, kwargs...)
if remoteurl === nothing
remoteurl = geturl(repo)
end

# Disable shallow fetches for local repos (not supported) or if LibGit2 doesn't support it
if depth > 0 && (is_local_repo(remoteurl) || !supports_shallow_clone())
depth = 0
end

fancyprint = can_fancyprint(io)
remoteurl = normalize_url(remoteurl)
printpkgstyle(io, :Updating, header === nothing ? "git-repo `$remoteurl`" : header)
Expand All @@ -174,15 +232,23 @@ function fetch(io::IO, repo::LibGit2.GitRepo, remoteurl = nothing; header = noth
return try
if use_cli_git()
let remoteurl = remoteurl
cmd = `git -C $(LibGit2.path(repo)) fetch -q $remoteurl $(only(refspecs))`
args = ["-C", LibGit2.path(repo), "fetch", "-q"]
depth > 0 && push!(args, "--depth=$depth")
push!(args, remoteurl, only(refspecs))
cmd = `git $args`
try
run(pipeline(cmd; stdout = devnull))
catch err
Pkg.Types.pkgerror("The command $(cmd) failed, error: $err")
end
end
else
return LibGit2.fetch(repo; remoteurl, callbacks, credentials, refspecs, kwargs...)
# Only pass depth if shallow clones are supported and depth > 0
if depth > 0
return LibGit2.fetch(repo; remoteurl, callbacks, credentials, refspecs, depth, kwargs...)
else
return LibGit2.fetch(repo; remoteurl, callbacks, credentials, refspecs, kwargs...)
end
end
catch err
err isa LibGit2.GitError || rethrow()
Expand Down
Loading