diff --git a/.gitignore b/.gitignore index 81a118f1dd..15252385a2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ docs/build /docs/src/repl.md .DS_Store /test/registries/* +/test/loaded_depot/* diff --git a/docs/src/api.md b/docs/src/api.md index 8577b7e55e..15814b193c 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -4,6 +4,16 @@ This section describes the function interface, or "API mode", for interacting with Pkg.jl. The function API is recommended for non-interactive usage, for example in scripts. +## General API Reference + +Certain options are generally useful and can be specified in any API call. +You can specify these options by setting keyword arguments. + +### Redirecting output + +Use the `io::IOBuffer` keyword argument to redirect Pkg output. +For example, `Pkg.add("Example"; io=devnull)` will discard any output produced by the `add` call. + ## Package API Reference In the REPL mode, packages (with associated version, UUID, URL etc) are parsed from strings, diff --git a/docs/src/artifacts.md b/docs/src/artifacts.md index b0f6dbe6b1..67aef4330f 100644 --- a/docs/src/artifacts.md +++ b/docs/src/artifacts.md @@ -1,5 +1,8 @@ # [**8.** Artifacts](@id Artifacts) +!!! compat "Julia 1.3" + Pkg's artifacts functionality requires at least Julia 1.3. + `Pkg` can install and manage containers of data that are not Julia packages. These containers can contain platform-specific binaries, datasets, text, or any other kind of data that would be convenient to place within an immutable, life-cycled datastore. These containers, (called "Artifacts") can be created locally, hosted anywhere, and automatically downloaded and unpacked upon installation of your Julia package. This mechanism is also used to provide the binary dependencies for packages built with [`BinaryBuilder.jl`](https://github.com/JuliaPackaging/BinaryBuilder.jl). diff --git a/docs/src/compatibility.md b/docs/src/compatibility.md index a31ef52a3b..271d503f1f 100644 --- a/docs/src/compatibility.md +++ b/docs/src/compatibility.md @@ -29,7 +29,7 @@ The union of multiple version specifiers can be formed by comma separating indiv [compat] Example = "1.2, 2" ``` -will result in `[1.2.0, 3.0.0)`. +will result in `[1.2.0, 3.0.0)`. Note leading zeros are treated differently, e.g. `Example = "0.2, 1"` would only result in `[0.2.0-0.3.0, 1.0.0-2.0.0]`. See the next section for more information on versions with leading zeros. ### Behavior of versions with leading zeros (0.0.x and 0.x.y) @@ -46,7 +46,7 @@ minor versions are not considered compatible, so the version 0.3.0 might have br Example = "0.0.1" ``` -results in a versionbound on `Example` as `[0.0.1, 0.02)` (which is equivalent to only the version 0.0.1), while the +results in a versionbound on `Example` as `[0.0.1, 0.0.2)` (which is equivalent to only the version 0.0.1), while the `[compat]` entry: ```julia diff --git a/docs/src/toml-files.md b/docs/src/toml-files.md index 1001d8a8c8..fc663af71f 100644 --- a/docs/src/toml-files.md +++ b/docs/src/toml-files.md @@ -6,8 +6,8 @@ and `Manifest.toml` are written in [TOML](https://github.com/toml-lang/toml) (he UUIDs etc. !!! note - The `Project.toml` and `Manifest.toml` files are not only used by the package manager, - they are also used by Julia's code loading, and determines e.g. what `using Example` + The `Project.toml` and `Manifest.toml` files are not only used by the package manager; + they are also used by Julia's code loading, and determine e.g. what `using Example` should do. For more details see the section about [Code Loading](https://docs.julialang.org/en/v1/manual/code-loading/) in the Julia manual. @@ -41,6 +41,9 @@ uuid = "7876af07-990d-54b4-ab0e-23690620f79a" ``` The `uuid` field is mandatory for packages. +!!! note + It is recommended that `UUIDs.uuid4()` is used to generate random UUIDs. + ### The `version` field @@ -74,7 +77,7 @@ Example = "7876af07-990d-54b4-ab0e-23690620f79a" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" ``` -Typically it is not needed to manually add entries to the `[deps]` section, this is instead +Typically it is not needed to manually add entries to the `[deps]` section; this is instead handled by Pkg operations such as `add`. @@ -105,10 +108,10 @@ julia = "1.1" ## `Manifest.toml` The manifest file is an absolute record of the state of the packages in the environment. -It includes exact information about (direct and indirect) dependencies of the project, and -given a `Project.toml` + `Manifest.toml` pair it is possible to instantiate the exact same -package environment, which is very useful for reproducibility, -see [`Pkg.instantiate`](@ref). +It includes exact information about (direct and indirect) dependencies of the project. +Given a `Project.toml` + `Manifest.toml` pair, it is possible to instantiate the exact same +package environment, which is very useful for reproducibility. +For the details, see [`Pkg.instantiate`](@ref). !!! note The `Manifest.toml` file is generated and maintained by Pkg and, in general, this file @@ -118,7 +121,7 @@ see [`Pkg.instantiate`](@ref). ### `Manifest.toml` entries Each dependency has its own section in the manifest file, and its content varies depending -on how the dependency was added to the environment, see the examples below. Every +on how the dependency was added to the environment. Every dependency section includes a combination of the following entries: * `uuid`: the [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) @@ -207,7 +210,7 @@ source tree is directly reflected. #### Pinned package -Pinned packages are also recorded in the manifest file, the resulting +Pinned packages are also recorded in the manifest file; the resulting dependency section for e.g. `pkg> add Example; pin Example` looks like: ```toml diff --git a/ext/TOML/src/TOML.jl b/ext/TOML/src/TOML.jl index 8d6ee145fc..3eced13ca1 100644 --- a/ext/TOML/src/TOML.jl +++ b/ext/TOML/src/TOML.jl @@ -12,7 +12,7 @@ module TOML "Convert `TOML.Table` to `Dict{String,Any}`" function table2dict(tbl::Union{Nothing,Table}) - tbl == nothing && return Dict{String,Any}() + tbl === nothing && return Dict{String,Any}() return table2dict(get(tbl)) end diff --git a/src/API.jl b/src/API.jl index 0e4cd05bd0..2952d50f3c 100644 --- a/src/API.jl +++ b/src/API.jl @@ -11,7 +11,7 @@ import LibGit2 import ..depots, ..depots1, ..logdir, ..devdir import ..Operations, ..Display, ..GitTools, ..Pkg, ..UPDATED_REGISTRY_THIS_SESSION using ..Types, ..TOML -using Pkg.Types: VersionTypes +using ..Types: VersionTypes using ..BinaryPlatforms using ..Artifacts: artifact_paths @@ -394,7 +394,7 @@ function gc(ctx::Context=Context(); collect_delay::Period=Day(30), kwargs...) # Collect the locations of every package referred to in this manifest pkg_dir(uuid, entry) = Operations.find_installed(entry.name, uuid, entry.tree_hash) - return [pkg_dir(u, e) for (u, e) in manifest if e.tree_hash != nothing] + return [pkg_dir(u, e) for (u, e) in manifest if e.tree_hash !== nothing] end function process_artifacts_toml(path) @@ -434,7 +434,7 @@ function gc(ctx::Context=Context(); collect_delay::Period=Day(30), kwargs...) for index_file in index_files # Check to see if it's still alive paths = process_func(index_file) - if paths != nothing + if paths !== nothing # Print the path of this beautiful, extant file to the user println(" $(Types.pathrepr(index_file))") append!(marked_paths, paths) @@ -682,7 +682,7 @@ function precompile(ctx::Context) for pkg in pkgids paths = Base.find_all_in_cache_path(pkg) sourcepath = Base.locate_package(pkg) - sourcepath == nothing && continue + sourcepath === nothing && continue # Heuristic for when precompilation is disabled occursin(r"\b__precompile__\(\s*false\s*\)", read(sourcepath, String)) && continue stale = true @@ -906,8 +906,18 @@ end UndoState() = UndoState(0, UndoState[]) const undo_entries = Dict{String, UndoState}() const max_undo_limit = 50 - -function add_snapshot_to_undo(env = EnvCache()) +const saved_initial_snapshot = Ref(false) + +function add_snapshot_to_undo(env=nothing) + # only attempt to take a snapshot if there is + # an active project to be found + if env === nothing + if Base.active_project() === nothing + return + else + env = EnvCache() + end + end state = get!(undo_entries, env.project_file) do UndoState() end @@ -929,7 +939,7 @@ function redo_undo(ctx, mode::Symbol, direction::Int) @assert direction == 1 || direction == -1 state = get(undo_entries, ctx.env.project_file, nothing) state === nothing && pkgerror("no undo state for current project") - state.idx == (mode == :redo ? 1 : length(state.entries)) && pkgerror("$mode: no more states left") + state.idx == (mode === :redo ? 1 : length(state.entries)) && pkgerror("$mode: no more states left") state.idx += direction snapshot = state.entries[state.idx] diff --git a/src/Artifacts.jl b/src/Artifacts.jl index 3ca9a6ac27..ccdec96eea 100644 --- a/src/Artifacts.jl +++ b/src/Artifacts.jl @@ -74,7 +74,7 @@ overriding to another artifact by its content-hash. """ const ARTIFACT_OVERRIDES = Ref{Union{Dict,Nothing}}(nothing) function load_overrides(;force::Bool = false) - if ARTIFACT_OVERRIDES[] != nothing && !force + if ARTIFACT_OVERRIDES[] !== nothing && !force return ARTIFACT_OVERRIDES[] end @@ -197,6 +197,9 @@ end Creates a new artifact by running `f(artifact_path)`, hashing the result, and moving it to the artifact store (`~/.julia/artifacts` on a typical installation). Returns the identifying tree hash of this artifact. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function create_artifact(f::Function) # Ensure the `artifacts` directory exists in our default depot @@ -245,7 +248,7 @@ function artifact_paths(hash::SHA1; honor_overrides::Bool=true) # First, check to see if we've got an override: if honor_overrides override = query_override(hash) - if override != nothing + if override !== nothing return [override] end end @@ -258,6 +261,9 @@ end Given an artifact (identified by SHA1 git tree hash), return its installation path. If the artifact does not exist, returns the location it would be installed to. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function artifact_path(hash::SHA1; honor_overrides::Bool=true) # Get all possible paths (rooted in all depots) @@ -280,6 +286,9 @@ end Returns whether or not the given artifact (identified by its sha1 git tree hash) exists on-disk. Note that it is possible that the given artifact exists in multiple locations (e.g. within multiple depots). + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function artifact_exists(hash::SHA1; honor_overrides::Bool=true) return any(isdir.(artifact_paths(hash; honor_overrides=honor_overrides))) @@ -296,9 +305,12 @@ will never attempt to remove an overridden artifact. In general, we recommend that you use `Pkg.gc()` to manage artifact installations and do not use `remove_artifact()` directly, as it can be difficult to know if an artifact is being used by another package. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function remove_artifact(hash::SHA1) - if query_override(hash) != nothing + if query_override(hash) !== nothing # We never remove overridden artifacts. return end @@ -318,11 +330,14 @@ end Verifies that the given artifact (identified by its SHA1 git tree hash) is installed on- disk, and retains its integrity. If the given artifact is overridden, skips the verification unless `honor_overrides` is set to `true`. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function verify_artifact(hash::SHA1; honor_overrides::Bool=false) # Silently skip overridden artifacts unless we really ask for it if !honor_overrides - if query_override(hash) != nothing + if query_override(hash) !== nothing return true end end @@ -342,10 +357,13 @@ end Archive an artifact into a tarball stored at `tarball_path`, returns the SHA256 of the resultant tarball as a hexidecimal string. Throws an error if the artifact does not exist. If the artifact is overridden, throws an error unless `honor_overrides` is set. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function archive_artifact(hash::SHA1, tarball_path::String; honor_overrides::Bool=false) if !honor_overrides - if query_override(hash) != nothing + if query_override(hash) !== nothing error("Will not archive an overridden artifact unless `honor_overrides` is set!") end end @@ -425,16 +443,16 @@ function pack_platform!(meta::Dict, p::Platform) ) meta["os"] = os_map[typeof(p)] meta["arch"] = string(arch(p)) - if libc(p) != nothing + if libc(p) !== nothing meta["libc"] = string(libc(p)) end - if libgfortran_version(p) != nothing + if libgfortran_version(p) !== nothing meta["libgfortran_version"] = string(libgfortran_version(p)) end - if libstdcxx_version(p) != nothing + if libstdcxx_version(p) !== nothing meta["libstdcxx_version"] = string(libstdcxx_version(p)) end - if cxxstring_abi(p) != nothing + if cxxstring_abi(p) !== nothing meta["cxxstring_abi"] = string(cxxstring_abi(p)) end end @@ -450,10 +468,26 @@ function load_artifacts_toml(artifacts_toml::String; pkg_uuid::Union{Base.UUID,Nothing} = nothing) artifact_dict = parse_toml(artifacts_toml) + # Process overrides for this `pkg_uuid` + process_overrides(artifact_dict, pkg_uuid) + return artifact_dict +end + +""" + process_overrides(artifact_dict::Dict, pkg_uuid::Base.UUID) + +When loading an `Artifacts.toml` file, we must check `Override.toml` files to see if any +of the artifacts within it have been overridden by UUID. If they have, we honor the +overrides by inspecting the hashes of the targeted artifacts, then overriding them to +point to the given override, punting the actual redirection off to the hash-based +override system. This does not modify the `artifact_dict` object, it merely dynamically +adds more hash-based overrides as `Artifacts.toml` files that are overridden are loaded. +""" +function process_overrides(artifact_dict::Dict, pkg_uuid::Base.UUID) # Insert just-in-time hash overrides by looking up the names of anything we need to # override for this UUID, and inserting new overrides for those hashes. overrides = load_overrides() - if pkg_uuid != nothing && haskey(overrides[:UUID], pkg_uuid) + if haskey(overrides[:UUID], pkg_uuid) pkg_overrides = overrides[:UUID][pkg_uuid] for name in keys(artifact_dict) @@ -474,10 +508,12 @@ function load_artifacts_toml(artifacts_toml::String; end end end - return artifact_dict end +# If someone tries to call process_overrides() with `nothing`, do exactly that +process_overrides(artifact_dict::Dict, pkg_uuid::Nothing) = nothing + """ artifact_meta(name::String, artifacts_toml::String; platform::Platform = platform_key_abi(), @@ -486,6 +522,9 @@ end Get metadata about a given artifact (identified by name) stored within the given `(Julia)Artifacts.toml` file. If the artifact is platform-specific, use `platform` to choose the most appropriate mapping. If none is found, return `nothing`. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function artifact_meta(name::String, artifacts_toml::String; platform::Platform = platform_key_abi(), @@ -517,7 +556,7 @@ function artifact_meta(name::String, artifact_dict::Dict, artifacts_toml::String end # This is such a no-no, we are going to call it out right here, right now. - if meta != nothing && !haskey(meta, "git-tree-sha1") + if meta !== nothing && !haskey(meta, "git-tree-sha1") @error("Invalid artifacts file at $(artifacts_toml): artifact '$name' contains no `git-tree-sha1`!") return nothing end @@ -531,6 +570,9 @@ end Thin wrapper around `artifact_meta()` to return the hash of the specified, platform- collapsed artifact. Returns `nothing` if no mapping can be found. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function artifact_hash(name::String, artifacts_toml::String; platform::Platform = platform_key_abi(), @@ -561,6 +603,9 @@ URLs will be listed as possible locations where this artifact can be obtained. is set to `true`, even if download information is available, this artifact will not be downloaded until it is accessed via the `artifact"name"` syntax, or `ensure_artifact_installed()` is called upon it. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function bind_artifact!(artifacts_toml::String, name::String, hash::SHA1; platform::Union{Platform,Nothing} = nothing, @@ -596,7 +641,7 @@ function bind_artifact!(artifacts_toml::String, name::String, hash::SHA1; # Integrate download info, if it is given. We represent the download info as a # vector of dicts, each with its own `url` and `sha256`, since different tarballs can # expand to the same tree hash. - if download_info != nothing + if download_info !== nothing meta["download"] = [ Dict("url" => dl[1], "sha256" => dl[2], @@ -604,7 +649,7 @@ function bind_artifact!(artifacts_toml::String, name::String, hash::SHA1; ] end - if platform == nothing + if platform === nothing artifact_dict[name] = meta else # Add platform-specific keys to our `meta` dict @@ -639,6 +684,9 @@ end Unbind the given `name` from an `(Julia)Artifacts.toml` file. Silently fails if no such binding exists within the file. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function unbind_artifact!(artifacts_toml::String, name::String; platform::Union{Platform,Nothing} = nothing) @@ -647,7 +695,7 @@ function unbind_artifact!(artifacts_toml::String, name::String; return end - if platform == nothing + if platform === nothing delete!(artifact_dict, name) else artifact_dict[name] = filter( @@ -667,6 +715,9 @@ end verbose::Bool = false) Download/install an artifact into the artifact store. Returns `true` on success. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function download_artifact( tree_hash::SHA1, @@ -740,6 +791,9 @@ end Given the path to a `.jl` file, (such as the one returned by `__source__.file` in a macro context), find the `(Julia)Artifacts.toml` that is contained within the containing project (if it exists), otherwise return `nothing`. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function find_artifacts_toml(path::String) if !isdir(path) @@ -779,6 +833,9 @@ end Ensures an artifact is installed, downloading it via the download information stored in `artifacts_toml` if necessary. Throws an error if unable to install. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function ensure_artifact_installed(name::String, artifacts_toml::String; platform::Platform = platform_key_abi(), @@ -839,6 +896,9 @@ Installs all non-lazy artifacts from a given `(Julia)Artifacts.toml` file. `pack be provided to properly support overrides from `Overrides.toml` entries in depots. If `include_lazy` is set to `true`, then lazy packages will be installed as well. + +!!! compat "Julia 1.3" + This function requires at least Julia 1.3. """ function ensure_all_artifacts_installed(artifacts_toml::String; platform::Platform = platform_key_abi(), @@ -908,6 +968,26 @@ function extract_all_hashes(artifacts_toml::String; return hashes end +function do_artifact_str(name, artifact_dict, artifacts_toml, __module__) + local pkg_uuid = nothing + if haskey(Base.module_keys, __module__) + # Process overrides for this UUID, if we know what it is + process_overrides(artifact_dict, Base.module_keys[__module__].uuid) + end + + # Get platform once to avoid extra work + platform = platform_key_abi() + + # Get the metadata about this name for the requested platform + meta = artifact_meta(name, artifact_dict, artifacts_toml; platform=platform) + + if meta === nothing + error("Cannot locate artifact '$(name)' in '$(artifacts_toml)'") + end + + # This is the resultant value at the end of all things + return ensure_artifact_installed(name, meta, artifacts_toml; platform=platform) +end """ macro artifact_str(name) @@ -915,27 +995,33 @@ end Macro that is used to automatically ensure an artifact is installed, and return its location on-disk. Automatically looks the artifact up by name in the project's `(Julia)Artifacts.toml` file. Throws an error on inability to install the requested artifact. + +!!! compat "Julia 1.3" + This macro requires at least Julia 1.3. """ macro artifact_str(name) - return quote - local artifacts_toml = $(find_artifacts_toml)($(string(__source__.file))) - if artifacts_toml === nothing - error(string( - "Cannot locate '(Julia)Artifacts.toml' file when attempting to use artifact '", - $(esc(name)), - "' in '", - $(esc(__module__)), - "'", - )) - end + # Load Artifacts.toml at compile time, so that we don't have to use `__source__.file` + # at runtime, which gets stale if the `.ji` file is relocated. + local artifacts_toml = find_artifacts_toml(string(__source__.file)) + if artifacts_toml === nothing + error(string( + "Cannot locate '(Julia)Artifacts.toml' file when attempting to use artifact '", + name, + "' in '", + __module__, + "'", + )) + end - local pkg_uuid = nothing - if haskey(Base.module_keys, $(__module__)) - pkg_uuid = Base.module_keys[$(__module__)].uuid - end + local artifact_dict = load_artifacts_toml(artifacts_toml) + return quote + # Invalidate .ji file if Artifacts.toml file changes + Base.include_dependency($(artifacts_toml)) - # This is the resultant value at the end of all things - $(ensure_artifact_installed)($(esc(name)), artifacts_toml; pkg_uuid=pkg_uuid) + # Use invokelatest() to introduce a compiler barrier, preventing many backedges from being added + # and slowing down not only compile time, but also `.ji` load time. This is critical here, as + # artifact"" is used in other modules, so we don't want to be spreading backedges around everywhere. + Base.invokelatest(do_artifact_str, $name, $(artifact_dict), $(artifacts_toml), $__module__) end end diff --git a/src/BinaryPlatforms.jl b/src/BinaryPlatforms.jl index 46218293f8..6f3092005e 100644 --- a/src/BinaryPlatforms.jl +++ b/src/BinaryPlatforms.jl @@ -37,17 +37,17 @@ struct CompilerABI function CompilerABI(;libgfortran_version::Union{Nothing, VersionNumber} = nothing, libstdcxx_version::Union{Nothing, VersionNumber} = nothing, cxxstring_abi::Union{Nothing, Symbol} = nothing) - if libgfortran_version != nothing && (libgfortran_version < v"3" || + if libgfortran_version !== nothing && (libgfortran_version < v"3" || libgfortran_version >= v"6") throw(ArgumentError("Unsupported libgfortran '$libgfortran_version'")) end - if libstdcxx_version != nothing && (libstdcxx_version < v"3.4.0" || + if libstdcxx_version !== nothing && (libstdcxx_version < v"3.4.0" || libstdcxx_version >= v"3.5") throw(ArgumentError("Unsupported libstdc++ '$libstdcxx_version'")) end - if cxxstring_abi != nothing && !in(cxxstring_abi, [:cxx03, :cxx11]) + if cxxstring_abi !== nothing && !in(cxxstring_abi, [:cxx03, :cxx11]) throw(ArgumentError("Unsupported string ABI '$cxxstring_abi'")) end @@ -71,13 +71,13 @@ cxxstring_abi(cabi::CompilerABI) = cabi.cxxstring_abi function show(io::IO, cabi::CompilerABI) args = String[] - if cabi.libgfortran_version != nothing + if cabi.libgfortran_version !== nothing push!(args, "libgfortran_version=$(repr(cabi.libgfortran_version))") end - if cabi.libstdcxx_version != nothing + if cabi.libstdcxx_version !== nothing push!(args, "libstdcxx_version=$(repr(cabi.libstdcxx_version))") end - if cabi.cxxstring_abi != nothing + if cabi.cxxstring_abi !== nothing push!(args, "cxxstring_abi=$(repr(cabi.cxxstring_abi))") end write(io, "CompilerABI($(join(args, ", ")))") @@ -103,7 +103,7 @@ function gcc_version(cabi::CompilerABI, GCC_versions::Vector{VersionNumber}) # libgfortran3 -> GCC 4.X, 5.X, 6.X # libgfortran4 -> GCC 7.x # libgfortran5 -> GCC 8.X, 9.X - if cabi.libgfortran_version != nothing + if cabi.libgfortran_version !== nothing if cabi.libgfortran_version.major == 3 GCC_versions = filt_gcc_majver(4,5,6) elseif cabi.libgfortran_version.major == 4 @@ -117,7 +117,7 @@ function gcc_version(cabi::CompilerABI, GCC_versions::Vector{VersionNumber}) # mapping is conservative; it is often the case that we return a # version that is slightly lower than what is actually installed on # a system. - if cabi.libstdcxx_version != nothing + if cabi.libstdcxx_version !== nothing cxxvp = cabi.libstdcxx_version.patch # Is this platform so old that nothing is supported? if cxxvp < 19 @@ -148,7 +148,7 @@ function gcc_version(cabi::CompilerABI, GCC_versions::Vector{VersionNumber}) # :cxx03 binaries on GCC 5+, (although increasingly rare) so the only # filtering we do is that if the platform is explicitly :cxx11, we # disallow running on < GCC 5. - if cabi.cxxstring_abi != nothing && cabi.cxxstring_abi == :cxx11 + if cabi.cxxstring_abi !== nothing && cabi.cxxstring_abi === :cxx11 GCC_versions = filter(v -> v >= v"5", GCC_versions) end @@ -179,7 +179,7 @@ struct Linux <: Platform end # Auto-map the `call_abi` to be `eabihf` on armv7l - if call_abi === nothing && arch == :armv7l + if call_abi === nothing && arch === :armv7l call_abi = :eabihf end @@ -188,11 +188,11 @@ struct Linux <: Platform end # If we're constructing for armv7l, we MUST have the eabihf abi - if arch == :armv7l && call_abi != :eabihf + if arch === :armv7l && call_abi !== :eabihf throw(ArgumentError("armv7l Linux must use eabihf, not '$call_abi'")) end # ...and vice-versa - if arch != :armv7l && call_abi == :eabihf + if arch !== :armv7l && call_abi === :eabihf throw(ArgumentError("eabihf Linux is only on armv7l, not '$arch'!")) end @@ -280,7 +280,7 @@ struct FreeBSD <: Platform end # Auto-map the `call_abi` to be `eabihf` on armv7l - if call_abi === nothing && arch == :armv7l + if call_abi === nothing && arch === :armv7l call_abi = :eabihf end @@ -289,11 +289,11 @@ struct FreeBSD <: Platform end # If we're constructing for armv7l, we MUST have the eabihf abi - if arch == :armv7l && call_abi != :eabihf + if arch === :armv7l && call_abi !== :eabihf throw(ArgumentError("armv7l FreeBSD must use eabihf, not '$call_abi'")) end # ...and vice-versa - if arch != :armv7l && call_abi == :eabihf + if arch !== :armv7l && call_abi === :eabihf throw(ArgumentError("eabihf FreeBSD is only on armv7l, not '$arch'!")) end @@ -431,11 +431,11 @@ vendor_str(p::FreeBSD) = "-unknown-freebsd11.1" triplet(p::UnknownPlatform) = "unknown-unknown-unknown" # Helper functions for Linux and FreeBSD libc/abi mishmashes -arch_str(p::Platform) = (arch(p) == :armv7l) ? "arm" : string(arch(p)) +arch_str(p::Platform) = (arch(p) === :armv7l) ? "arm" : string(arch(p)) function libc_str(p::Platform) if libc(p) === nothing return "" - elseif libc(p) == :glibc + elseif libc(p) === :glibc return "-gnu" else return "-$(libc(p))" @@ -444,15 +444,15 @@ end call_abi_str(p::Platform) = (call_abi(p) === nothing) ? "" : string(call_abi(p)) function compiler_abi_str(cabi::CompilerABI) str = "" - if cabi.libgfortran_version != nothing + if cabi.libgfortran_version !== nothing str *= "-libgfortran$(cabi.libgfortran_version.major)" end - if cabi.libstdcxx_version != nothing + if cabi.libstdcxx_version !== nothing str *= "-libstdcxx$(libstdcxx_version(cabi).patch)" end - if cabi.cxxstring_abi != nothing + if cabi.cxxstring_abi !== nothing str *= "-$(cabi.cxxstring_abi)" end return str @@ -529,12 +529,12 @@ function platform_key_abi(machine::AbstractString) )) m = match(triplet_regex, machine) - if m != nothing + if m !== nothing # Helper function to find the single named field within the giant regex # that is not `nothing` for each mapping we give it. get_field(m, mapping) = begin for k in keys(mapping) - if m[k] != nothing + if m[k] !== nothing strk = string(k) # Convert our sentinel `nothing` values to actual `nothing` if endswith(strk, "_nothing") @@ -589,10 +589,10 @@ end function show(io::IO, p::Platform) write(io, "$(platform_name(p))($(repr(arch(p)))") - if libc(p) != nothing + if libc(p) !== nothing write(io, ", libc=$(repr(libc(p)))") end - if call_abi(p) != nothing + if call_abi(p) !== nothing write(io, ", call_abi=$(repr(call_abi(p)))") end if compiler_abi(p) != CompilerABI() @@ -724,7 +724,7 @@ function detect_libstdcxx_version() # Brute-force our way through GLIBCXX_* symbols to discover which version we're linked against hdl = Libdl.dlopen(first(libstdcxx_paths)) for minor_version in 26:-1:18 - if Libdl.dlsym(hdl, "GLIBCXX_3.4.$(minor_version)"; throw_error=false) != nothing + if Libdl.dlsym(hdl, "GLIBCXX_3.4.$(minor_version)"; throw_error=false) !== nothing Libdl.dlclose(hdl) return VersionNumber("3.4.$(minor_version)") end diff --git a/src/Display.jl b/src/Display.jl index 6e0f1a4d05..bd6a970607 100644 --- a/src/Display.jl +++ b/src/Display.jl @@ -153,10 +153,10 @@ end revstring(str::String) = occursin(r"\b([a-f0-9]{40})\b", str) ? str[1:7] : str vstring(ctx::Context, a::VerInfo) = - string((a.ver == nothing && a.hash != nothing) ? "[$(string(a.hash)[1:16])]" : "", - a.ver != nothing ? "v$(a.ver)" : "", - a.path != nothing ? " [$(pathrepr(a.path))]" : "", - a.repo != nothing ? " #$(revstring(a.repo.rev)) ($(a.repo.source))" : "", + string((a.ver === nothing && a.hash !== nothing) ? "[$(string(a.hash)[1:16])]" : "", + a.ver !== nothing ? "v$(a.ver)" : "", + a.path !== nothing ? " [$(pathrepr(a.path))]" : "", + a.repo !== nothing ? " #$(revstring(a.repo.rev)) ($(a.repo.source))" : "", a.pinned == true ? " ⚲" : "", ) @@ -165,9 +165,9 @@ Base.:(==)(a::VerInfo, b::VerInfo) = a.path == b.path ≈(a::VerInfo, b::VerInfo) = a.hash == b.hash && - (a.ver == nothing || b.ver == nothing || a.ver == b.ver) && + (a.ver === nothing || b.ver === nothing || a.ver == b.ver) && (a.pinned == b.pinned) && - (a.repo == nothing || b.repo == nothing || a.repo == b.repo) && + (a.repo === nothing || b.repo === nothing || a.repo == b.repo) && (a.path == b.path) struct DiffEntry @@ -193,12 +193,12 @@ function print_diff(io::IO, ctx::Context, diff::Vector{DiffEntry}, status=false) else if (x.old.hash === nothing || x.new.hash === nothing || x.old.hash != x.new.hash) && x.old.ver != x.new.ver - verb = x.old.ver == nothing || x.new.ver == nothing || + verb = x.old.ver === nothing || x.new.ver === nothing || x.old.ver == x.new.ver ? '~' : x.old.ver < x.new.ver ? '↑' : '↓' elseif x.old.ver == x.new.ver && x.old.pinned != x.new.pinned || x.old.path != x.new.path || - x.old.repo != nothing || x.new.repo != nothing + x.old.repo !== nothing || x.new.repo !== nothing verb = '~' else verb = '?' @@ -208,10 +208,10 @@ function print_diff(io::IO, ctx::Context, diff::Vector{DiffEntry}, status=false) vstring(ctx, x.new) : vstring(ctx, x.old) * " ⇒ " * vstring(ctx, x.new) end - elseif x.new != nothing + elseif x.new !== nothing verb = '+' vstr = vstring(ctx, x.new) - elseif x.old != nothing + elseif x.old !== nothing verb = '-' vstr = vstring(ctx, x.old) else diff --git a/src/GitTools.jl b/src/GitTools.jl index 4cfa13dba1..6da5b87b6c 100644 --- a/src/GitTools.jl +++ b/src/GitTools.jl @@ -124,7 +124,7 @@ end function clone(ctx, url, source_path; header=nothing, credentials=nothing, kwargs...) @assert !isdir(source_path) || isempty(readdir(source_path)) url = normalize_url(url) - Pkg.Types.printpkgstyle(ctx, :Cloning, header == nothing ? "git-repo `$url`" : header) + Pkg.Types.printpkgstyle(ctx, :Cloning, header === nothing ? "git-repo `$url`" : header) transfer_payload = MiniProgressBar(header = "Fetching:", color = Base.info_color()) callbacks = LibGit2.Callbacks( :transfer_progress => ( @@ -133,7 +133,7 @@ function clone(ctx, url, source_path; header=nothing, credentials=nothing, kwarg ) ) print(stdout, "\e[?25l") # disable cursor - if credentials == nothing + if credentials === nothing credentials = LibGit2.CachedCredentials() end mkpath(source_path) @@ -162,7 +162,7 @@ function fetch(ctx, repo::LibGit2.GitRepo, remoteurl=nothing; header=nothing, cr end end remoteurl = normalize_url(remoteurl) - Pkg.Types.printpkgstyle(ctx, :Updating, header == nothing ? "git-repo `$remoteurl`" : header) + Pkg.Types.printpkgstyle(ctx, :Updating, header === nothing ? "git-repo `$remoteurl`" : header) transfer_payload = MiniProgressBar(header = "Fetching:", color = Base.info_color()) callbacks = LibGit2.Callbacks( :transfer_progress => ( @@ -171,7 +171,7 @@ function fetch(ctx, repo::LibGit2.GitRepo, remoteurl=nothing; header=nothing, cr ) ) print(stdout, "\e[?25l") # disable cursor - if credentials == nothing + if credentials === nothing credentials = LibGit2.CachedCredentials() end try diff --git a/src/Operations.jl b/src/Operations.jl index 5f31595175..4b9e812f6b 100644 --- a/src/Operations.jl +++ b/src/Operations.jl @@ -363,7 +363,7 @@ function deps_graph(ctx::Context, uuid_to_name::Dict{UUID,String}, reqs::Resolve if uuid in keys(ctx.stdlibs) path = Types.stdlib_path(ctx.stdlibs[uuid]) proj_file = projectfile_path(path; strict=true) - @assert proj_file != nothing + @assert proj_file !== nothing proj = Types.read_package(proj_file) v = something(proj.version, VERSION) @@ -446,7 +446,7 @@ end ######################## function get_archive_url_for_version(url::String, ref) - if (m = match(r"https://github.com/(.*?)/(.*?).git", url)) != nothing + if (m = match(r"https://github.com/(.*?)/(.*?).git", url)) !== nothing return "https://api.github.com/repos/$(m.captures[1])/$(m.captures[2])/tarball/$(ref)" end return nothing @@ -560,7 +560,7 @@ end function download_artifacts(pkgs::Vector{PackageSpec}; platform::Platform=platform_key_abi(), verbose::Bool=false) # Filter out packages that have no source_path() - pkg_roots = String[p for p in source_path.(pkgs) if p != nothing] + pkg_roots = String[p for p in source_path.(pkgs) if p !== nothing] return download_artifacts(pkg_roots; platform=platform, verbose=verbose) end @@ -666,7 +666,7 @@ function download_source(ctx::Context, pkgs::Vector{PackageSpec}, sprint(Base.showerror, exc_or_success, bt_or_path)) success, path = exc_or_success, bt_or_path if success - vstr = pkg.version != nothing ? "v$(pkg.version)" : "[$h]" + vstr = pkg.version !== nothing ? "v$(pkg.version)" : "[$h]" printpkgstyle(ctx, :Installed, string(rpad(pkg.name * " ", max_name + 2, "─"), " ", vstr)) else push!(missed_packages, (pkg, path)) @@ -680,7 +680,7 @@ function download_source(ctx::Context, pkgs::Vector{PackageSpec}, uuid = pkg.uuid install_git(ctx, pkg.uuid, pkg.name, pkg.tree_hash, urls[uuid], pkg.version::VersionNumber, path) readonly && set_readonly(path) - vstr = pkg.version != nothing ? "v$(pkg.version)" : "[$h]" + vstr = pkg.version !== nothing ? "v$(pkg.version)" : "[$h]" printpkgstyle(ctx, :Installed, string(rpad(pkg.name * " ", max_name + 2, "─"), " ", vstr)) end @@ -839,6 +839,7 @@ function build_versions(ctx::Context, uuids::Vector{UUID}; might_need_to_resolve rpad(name * " ", max_name + 1, "─") * "→ " * Types.pathrepr(log_file)) sandbox(ctx, pkg, source_path, builddir(source_path)) do + flush(stdout) ok = open(log_file, "w") do log std = verbose ? ctx.io : log success(pipeline(gen_build_code(buildfile(source_path)), @@ -1375,6 +1376,7 @@ function test(ctx::Context, pkgs::Vector{PackageSpec}; println(ctx.io, "Running sandbox") test_fn !== nothing && test_fn() Display.status(Context(), mode=PKGMODE_PROJECT) + flush(stdout) try run(gen_test_code(testfile(source_path); coverage=coverage, julia_args=julia_args, test_args=test_args)) printpkgstyle(ctx, :Testing, pkg.name * " tests passed ") diff --git a/src/Pkg.jl b/src/Pkg.jl index ebd4c1d7cf..2515ba93be 100644 --- a/src/Pkg.jl +++ b/src/Pkg.jl @@ -447,7 +447,7 @@ const PackageSpec = API.Package ) Set the protocol used to access hosted packages when `add`ing a url or `develop`ing a package. -Defaults to delegating the choice to the package developer (`protocol == nothing`). +Defaults to delegating the choice to the package developer (`protocol === nothing`). Other choices for `protocol` are `"https"` or `"git"`. # Examples @@ -514,7 +514,6 @@ function __init__() end end end - API.add_snapshot_to_undo() end ################## diff --git a/src/PlatformEngines.jl b/src/PlatformEngines.jl index b4f77f9dda..6f90367088 100644 --- a/src/PlatformEngines.jl +++ b/src/PlatformEngines.jl @@ -198,7 +198,7 @@ function probe_platform_engines!(;verbose::Bool = false) unpack_7z = (exe7z) -> begin return (tarball_path, out_path, excludelist = nothing) -> pipeline(pipeline(`$exe7z x $(tarball_path) -y -so`, - `$exe7z x -si -y -ttar -o$(out_path) $(excludelist == nothing ? [] : "-x@$(excludelist)")`); + `$exe7z x -si -y -ttar -o$(out_path) $(excludelist === nothing ? [] : "-x@$(excludelist)")`); stdout=devnull, stderr=devnull) end package_7z = (exe7z) -> begin @@ -320,7 +320,7 @@ function probe_platform_engines!(;verbose::Bool = false) elseif endswith(tarball_path, ".bz2") Jjz = "j" end - return `$tar_cmd -x$(Jjz)f $(tarball_path) -C$(out_path) $(excludelist == nothing ? [] : "-X$(excludelist)")` + return `$tar_cmd -x$(Jjz)f $(tarball_path) -C$(out_path) $(excludelist === nothing ? [] : "-X$(excludelist)")` end package_tar = (in_path, tarball_path) -> begin Jjz = "z" diff --git a/src/REPLMode/REPLMode.jl b/src/REPLMode/REPLMode.jl index 8bd4efb0a9..3d678e1294 100644 --- a/src/REPLMode/REPLMode.jl +++ b/src/REPLMode/REPLMode.jl @@ -141,7 +141,7 @@ struct Option Option(val::AbstractString) = new(val, nothing) Option(val::AbstractString, arg::Union{Nothing,String}) = new(val, arg) end -Base.show(io::IO, opt::Option) = print(io, "--$(opt.val)", opt.argument == nothing ? "" : "=$(opt.argument)") +Base.show(io::IO, opt::Option) = print(io, "--$(opt.val)", opt.argument === nothing ? "" : "=$(opt.argument)") wrap_option(option::String) = length(option) == 1 ? "-$option" : "--$option" is_opt(word::AbstractString) = first(word) == '-' && word != "-" @@ -542,7 +542,7 @@ function create_mode(repl, main) end repl_keymap = Dict() - if shell_mode != nothing + if shell_mode !== nothing repl_keymap[';'] = function (s,o...) if isempty(s) || position(LineEdit.buffer(s)) == 0 buf = copy(LineEdit.buffer(s)) diff --git a/src/REPLMode/completions.jl b/src/REPLMode/completions.jl index 9064d0e9b7..8f296175a8 100644 --- a/src/REPLMode/completions.jl +++ b/src/REPLMode/completions.jl @@ -145,10 +145,17 @@ function complete_argument(spec::CommandSpec, options::Vector{String}, end function _completions(input, final, offset, index) - words = tokenize(input)[end] - word_count = length(words) - statement, partial = core_parse(words) - final && (partial = "") # last token is finalized -> no partial + statement, word_count, partial = nothing, nothing, nothing + try + words = tokenize(input)[end] + word_count = length(words) + statement, partial = core_parse(words) + if final + partial = "" # last token is finalized -> no partial + end + catch + return String[], 0:-1, false + end # number of tokens which specify the command command_size = count([statement.super !== nothing, true]) command_is_focused() = !((word_count == command_size && final) || word_count > command_size) diff --git a/src/Resolve/graphtype.jl b/src/Resolve/graphtype.jl index cbdb3c0ba9..2ff1f07d84 100644 --- a/src/Resolve/graphtype.jl +++ b/src/Resolve/graphtype.jl @@ -616,7 +616,7 @@ function log_event_req!(graph::Graph, rp::UUID, rvs::VersionSpec, reason) id = pkgID(rp, rlog) msg = "restricted to versions $rvs by " if reason isa Symbol - @assert reason == :explicit_requirement + @assert reason === :explicit_requirement other_entry = nothing msg *= "an explicit requirement" else @@ -749,10 +749,10 @@ function log_event_maxsumsolved!(graph::Graph, p0::Int, s0::Int, why::Symbol) p = pkgs[p0] id = pkgID(p, rlog) if s0 == spp[p0] - @assert why == :uninst + @assert why === :uninst msg = "determined to be unneeded by the solver" else - @assert why == :constr + @assert why === :constr if s0 == spp[p0] - 1 msg = "set by the solver to its maximum version: $(pvers[p0][s0])" else @@ -844,9 +844,9 @@ Show the full resolution log. The `view` keyword controls how the events are dis function showlog(io::IO, rlog::ResolveLog; view::Symbol = :plain) view ∈ [:plain, :tree, :chronological] || throw(ArgumentError("the view argument should be `:plain`, `:tree` or `:chronological`")) println(io, "Resolve log:") - view == :chronological && return showlogjournal(io, rlog) + view === :chronological && return showlogjournal(io, rlog) seen = IdDict() - recursive = (view == :tree) + recursive = (view === :tree) _show(io, rlog, rlog.globals, _logindent, seen, false) initentries = [event[1] for event in rlog.init.events] for entry in sort!(initentries, by=(entry->pkgID(entry.pkg, rlog))) @@ -872,7 +872,7 @@ the same as for `showlog(io, rlog)`); the default is `:tree`. function showlog(io::IO, rlog::ResolveLog, p::UUID; view::Symbol = :tree) view ∈ [:plain, :tree] || throw(ArgumentError("the view argument should be `:plain` or `:tree`")) entry = rlog.pool[p] - if view == :tree + if view === :tree _show(io, rlog, entry, _logindent, IdDict(entry=>true), true) else entries = ResolveLogEntry[entry] diff --git a/src/Types.jl b/src/Types.jl index 0931bf7451..7591c952bc 100644 --- a/src/Types.jl +++ b/src/Types.jl @@ -182,7 +182,7 @@ function find_project_file(env::Union{Nothing,String}=nothing) project_file = nothing if env isa Nothing project_file = Base.active_project() - project_file == nothing && pkgerror("no active project") + project_file === nothing && pkgerror("no active project") elseif startswith(env, '@') project_file = Base.load_path_expand(env) project_file === nothing && pkgerror("package environment does not exist: $env") @@ -281,8 +281,10 @@ function EnvCache(env::Union{Nothing,String}=nothing) git = ispath(joinpath(project_dir, ".git")) ? project_dir : nothing # read project file project = read_project(project_file) - # initiaze project package + # initialize project package if any(x -> x !== nothing, [project.name, project.uuid, project.version]) + project.name === nothing && pkgerror("project appears to be a package but has no name") + project.uuid === nothing && pkgerror("project appears to be a package but has no uuid") project_package = PackageSpec( name = project.name, uuid = project.uuid, @@ -301,7 +303,8 @@ function EnvCache(env::Union{Nothing,String}=nothing) uuids = Dict{String,Vector{UUID}}() paths = Dict{UUID,Vector{String}}() names = Dict{UUID,Vector{String}}() - return EnvCache(env, + + env′ = EnvCache(env, git, project_file, manifest_file, @@ -313,6 +316,14 @@ function EnvCache(env::Union{Nothing,String}=nothing) uuids, paths, names,) + + # Save initial environment for undo/redo functionality + if !Pkg.API.saved_initial_snapshot[] + Pkg.API.add_snapshot_to_undo(env′) + Pkg.API.saved_initial_snapshot[] = true + end + + return env′ end include("project.jl") @@ -491,12 +502,12 @@ function handle_repo_develop!(ctx::Context, pkg::PackageSpec, shared::Bool) uuid = get(ctx.env.project.deps, pkg.name, nothing) if uuid !== nothing entry = manifest_info(ctx, uuid) - if entry !== nothing + if entry !== nothing pkg.repo.source = entry.repo.source end end end - + # Still haven't found the source, try get it from the registry if pkg.repo.source === nothing set_repo_source_from_registry!(ctx, pkg) @@ -589,7 +600,7 @@ function handle_repo_add!(ctx::Context, pkg::PackageSpec) LibGit2.with(GitTools.ensure_clone(ctx, add_repo_cache_path(repo_source), repo_source; isbare=true)) do repo # If the user didn't specify rev, assume they want the default (master) branch if on a branch, otherwise the current commit - if pkg.repo.rev == nothing + if pkg.repo.rev === nothing pkg.repo.rev = LibGit2.isattached(repo) ? LibGit2.branch(repo) : string(LibGit2.GitHash(LibGit2.head(repo))) end @@ -631,7 +642,7 @@ function handle_repo_add!(ctx::Context, pkg::PackageSpec) # check to see if the package exists at its canonical path. version_path = Pkg.Operations.source_path(pkg) isdir(version_path) && return false - + # Otherwise, move the temporary path into its correct place and set read only mkpath(version_path) mv(temp_path, version_path; force=true) @@ -1255,7 +1266,7 @@ function registered_name(ctx::Context, uuid::UUID)::Union{Nothing,String} values = registered_info(ctx, uuid, "name") name = nothing for value in values - name == nothing && (name = value[2]) + name === nothing && (name = value[2]) name != value[2] && pkgerror("package `$uuid` has multiple registered name values: $name, $(value[2])") end return name diff --git a/src/backwards_compatible_isolation.jl b/src/backwards_compatible_isolation.jl index ca462c23fd..a7c6da064d 100644 --- a/src/backwards_compatible_isolation.jl +++ b/src/backwards_compatible_isolation.jl @@ -1,7 +1,7 @@ function _update_manifest(ctx::Context, pkg::PackageSpec, hash::Union{SHA1, Nothing}) env = ctx.env uuid, name, version, path, special_action, repo = pkg.uuid, pkg.name, pkg.version, pkg.path, pkg.special_action, pkg.repo - hash === nothing && @assert (path != nothing || pkg.uuid in keys(ctx.stdlibs) || pkg.repo.source != nothing) + hash === nothing && @assert (path !== nothing || pkg.uuid in keys(ctx.stdlibs) || pkg.repo.source !== nothing) # TODO I think ^ assertion is wrong, add-repo should have a hash entry = get!(env.manifest, uuid, Types.PackageEntry()) entry.name = name @@ -81,7 +81,7 @@ function _resolve_versions!( else ver = VersionSpec() end - if uuid_idx != nothing + if uuid_idx !== nothing pkg = pkgs[uuid_idx] if entry !== nothing && pkg.special_action != PKGSPEC_FREED && entry.pinned # This is a pinned package, fix its version @@ -231,7 +231,7 @@ function apply_versions(ctx::Context, pkgs::Vector{PackageSpec}, hashes::Dict{UU end try success = install_archive(urls[pkg.uuid], hashes[pkg.uuid], path) - if success && mode == :add + if success && mode === :add set_readonly(path) # In add mode, files should be read-only end if ctx.use_only_tarballs_for_downloads && !success @@ -252,7 +252,7 @@ function apply_versions(ctx::Context, pkgs::Vector{PackageSpec}, hashes::Dict{UU sprint(Base.showerror, exc_or_success, bt_or_path)) success, path = exc_or_success, bt_or_path if success - vstr = pkg.version != nothing ? "v$(pkg.version)" : "[$h]" + vstr = pkg.version !== nothing ? "v$(pkg.version)" : "[$h]" printpkgstyle(ctx, :Installed, string(rpad(pkg.name * " ", max_name + 2, "─"), " ", vstr)) else push!(missed_packages, (pkg, path)) @@ -265,10 +265,10 @@ function apply_versions(ctx::Context, pkgs::Vector{PackageSpec}, hashes::Dict{UU for (pkg, path) in missed_packages uuid = pkg.uuid install_git(ctx, pkg.uuid, pkg.name, hashes[uuid], urls[uuid], pkg.version::VersionNumber, path) - if mode == :add + if mode === :add set_readonly(path) end - vstr = pkg.version != nothing ? "v$(pkg.version)" : "[$h]" + vstr = pkg.version !== nothing ? "v$(pkg.version)" : "[$h]" printpkgstyle(ctx, :Installed, string(rpad(pkg.name * " ", max_name + 2, "─"), " ", vstr)) end @@ -560,7 +560,7 @@ function backwards_compatibility_for_test( if !Types.is_project_uuid(ctx, pkg.uuid) Display.status(localctx, mode=PKGMODE_MANIFEST) end - + flush(stdout) run_test() end end @@ -603,6 +603,7 @@ function backwards_compat_for_build(ctx::Context, pkg::PackageSpec, build_file:: end with_dependencies_loadable_at_toplevel(ctx, pkg; might_need_to_resolve=might_need_to_resolve) do localctx + flush(stdout) run_build() end end diff --git a/src/generate.jl b/src/generate.jl index d299995ce6..3959af2593 100644 --- a/src/generate.jl +++ b/src/generate.jl @@ -27,23 +27,23 @@ function project(ctx::Context, pkg::String, dir::String) gitmail = LibGit2.getconfig("user.email", "") isempty(gitmail) || (email = gitmail) - if name == nothing + if name === nothing for env in ["GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME", "USER", "USERNAME", "NAME"] name = get(ENV, env, nothing) - name != nothing && break + name !== nothing && break end end - name == nothing && (name = "Unknown") + name === nothing && (name = "Unknown") - if email == nothing + if email === nothing for env in ["GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL", "EMAIL"]; email = get(ENV, env, nothing) - email != nothing && break + email !== nothing && break end end - authors = ["$name " * (email == nothing ? "" : "<$email>")] + authors = ["$name " * (email === nothing ? "" : "<$email>")] uuid = UUIDs.uuid4() genfile(ctx, pkg, dir, "Project.toml") do io diff --git a/src/versions.jl b/src/versions.jl index 49fbe792fd..425e873433 100644 --- a/src/versions.jl +++ b/src/versions.jl @@ -111,9 +111,9 @@ VersionRange(v::VersionNumber) = VersionRange(VersionBound(v)) function VersionRange(s::AbstractString) m = match(r"^\s*v?((?:\d+(?:\.\d+)?(?:\.\d+)?)|\*)(?:\s*-\s*v?((?:\d+(?:\.\d+)?(?:\.\d+)?)|\*))?\s*$", s) - m == nothing && throw(ArgumentError("invalid version range: $(repr(s))")) + m === nothing && throw(ArgumentError("invalid version range: $(repr(s))")) lower = VersionBound(m.captures[1]) - upper = m.captures[2] != nothing ? VersionBound(m.captures[2]) : lower + upper = m.captures[2] !== nothing ? VersionBound(m.captures[2]) : lower return VersionRange(lower, upper) end @@ -157,7 +157,7 @@ function Base.union!(ranges::Vector{<:VersionRange}) k0 = 1 ks = findfirst(!isempty, ranges) - ks == nothing && return empty!(ranges) + ks === nothing && return empty!(ranges) lo, up, k0 = ranges[ks].lower, ranges[ks].upper, 1 for k = (ks + 1):l @@ -287,7 +287,7 @@ function semver_interval(m::RegexMatch) # Default type is :caret vertyp = (typ == "" || typ == "^") ? :caret : :tilde v0 = VersionBound((major, minor, patch)) - if vertyp == :caret + if vertyp === :caret if major != 0 return VersionRange(v0, VersionBound((v0[1],))) elseif minor != 0 diff --git a/test/new.jl b/test/new.jl index 57389ea025..491a0937a9 100644 --- a/test/new.jl +++ b/test/new.jl @@ -1740,6 +1740,20 @@ end @test isfile(joinpath(dir, "JuliaManifest.toml")) end end + # missing name/uuid for package project + isolate(loaded_depot=true) do; mktempdir() do tmp + project = joinpath(tmp, "Project.toml") + Base.ACTIVE_PROJECT[] = project + # missing name + write(project, "\"uuid\" = \"ed688b04-e580-4bf1-bc13-c3be32aba1f6\"") + @test_throws PkgError("project appears to be a package but has no name") Pkg.Types.EnvCache() + # missing uuid + write(project, "\"name\" = \"PackageName\"") + @test_throws PkgError("project appears to be a package but has no uuid") Pkg.Types.EnvCache() + # missing name and uuid + write(project, "\"version\" = \"1.0.0\"") + @test_throws PkgError("project appears to be a package but has no name") Pkg.Types.EnvCache() + end end end # diff --git a/test/pkg.jl b/test/pkg.jl index 0febb3d376..93789987a2 100644 --- a/test/pkg.jl +++ b/test/pkg.jl @@ -625,7 +625,7 @@ end # Example Pkg.add(TEST_PKG.name) @test haskey(Pkg.dependencies(), TEST_PKG.uuid) - # + # Pkg.undo() @test !haskey(Pkg.dependencies(), TEST_PKG.uuid) # Example @@ -653,7 +653,7 @@ end # Example, Unicode Pkg.redo() @test haskey(Pkg.dependencies(), unicode_uuid) - + # Example Pkg.undo() diff --git a/test/project/good/pkg.toml b/test/project/good/pkg.toml index ed4c5a33a1..81b14b5d7a 100644 --- a/test/project/good/pkg.toml +++ b/test/project/good/pkg.toml @@ -3,6 +3,7 @@ keywords = ["package", "management"] license = "MIT" desc = "The next-generation Julia package manager." version = "1.0.0" +uuid = "3ac81be6-66a4-43e7-a94c-2ce720faec7d" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" diff --git a/test/repl.jl b/test/repl.jl index 7a149ad43e..904f45ba31 100644 --- a/test/repl.jl +++ b/test/repl.jl @@ -391,6 +391,9 @@ temp_pkg_dir() do project_path; cd(project_path) do # invalid options c, r = test_complete("rm -rf ") @test isempty(c) + + # parse errors should not throw + _ = test_complete("add \"Foo") end # testset end end diff --git a/test/runtests.jl b/test/runtests.jl index 9f06b89d61..ffec3fa0f7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,6 +4,9 @@ module PkgTests import Pkg +# Make sure to not start with an outdated registry +rm(joinpath(@__DIR__, "registries"); force = true, recursive = true) + include("utils.jl") include("new.jl") include("pkg.jl")