Skip to content

Commit

Permalink
Add back [pieces of] Pkg2 for bin/loadmeta.jl
Browse files Browse the repository at this point in the history
  • Loading branch information
carlobaldassi committed Dec 9, 2017
1 parent 537a641 commit 6370caf
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 3 deletions.
45 changes: 45 additions & 0 deletions bin/Pkg2/Pkg2.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Trimmed-down code from Pkg2 with only the essential parts needed by loadmeta.jl

module Pkg2

struct PkgError <: Exception
msg::AbstractString
ex::Nullable{Exception}
end
PkgError(msg::AbstractString) = PkgError(msg, Nullable{Exception}())
function Base.showerror(io::IO, pkgerr::PkgError)
print(io, pkgerr.msg)
if !isnull(pkgerr.ex)
pkgex = get(pkgerr.ex)
if isa(pkgex, CompositeException)
for cex in pkgex
print(io, "\n=> ")
showerror(io, cex)
end
else
print(io, "\n")
showerror(io, pkgex)
end
end
end

# DIR
const DIR_NAME = ".julia"
_pkgroot() = abspath(get(ENV,"JULIA_PKGDIR",joinpath(homedir(),DIR_NAME)))
isversioned(p::AbstractString) = ((x,y) = (VERSION.major, VERSION.minor); basename(p) == "v$x.$y")

function dir()
b = _pkgroot()
x, y = VERSION.major, VERSION.minor
d = joinpath(b,"v$x.$y")
if isdir(d) || !isdir(b) || !isdir(joinpath(b, "METADATA"))
return d
end
return b
end
dir(pkg::AbstractString...) = normpath(dir(),pkg...)

include("types.jl")
include("reqs.jl")

end
46 changes: 46 additions & 0 deletions bin/Pkg2/reqs.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

module Reqs

import Base: ==
import ..PkgError
using ..Types

# representing lines of REQUIRE files

abstract type Line end
struct Comment <: Line
content::AbstractString
end
struct Requirement <: Line
content::AbstractString
package::AbstractString
versions::VersionSet
system::Vector{AbstractString}

function Requirement(content::AbstractString)
fields = split(replace(content, r"#.*$", ""))
system = AbstractString[]
while !isempty(fields) && fields[1][1] == '@'
push!(system,shift!(fields)[2:end])
end
isempty(fields) && throw(PkgError("invalid requires entry: $content"))
package = shift!(fields)
all(field->ismatch(Base.VERSION_REGEX, field), fields) ||
throw(PkgError("invalid requires entry for $package: $content"))
versions = VersionNumber[fields...]
issorted(versions) || throw(PkgError("invalid requires entry for $package: $content"))
new(content, package, VersionSet(versions), system)
end
end

function read(readable::Union{IO,Base.AbstractCmd})
lines = Line[]
for line in eachline(readable)
push!(lines, ismatch(r"^\s*(?:#|$)", line) ? Comment(line) : Requirement(line))
end
return lines
end
read(file::AbstractString) = isfile(file) ? open(read,file) : Line[]

end # module
131 changes: 131 additions & 0 deletions bin/Pkg2/types.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

module Types

export VersionInterval, VersionSet
import Base: show, isempty, in, intersect, union!, union, ==, hash, copy, deepcopy_internal

import Pkg3.equalto
import Pkg3.iswindows

struct VersionInterval
lower::VersionNumber
upper::VersionNumber
end
VersionInterval(lower::VersionNumber) = VersionInterval(lower,typemax(VersionNumber))
VersionInterval() = VersionInterval(typemin(VersionNumber))

show(io::IO, i::VersionInterval) = print(io, "[$(i.lower),$(i.upper))")
isempty(i::VersionInterval) = i.upper <= i.lower
in(v::VersionNumber, i::VersionInterval) = i.lower <= v < i.upper
intersect(a::VersionInterval, b::VersionInterval) = VersionInterval(max(a.lower,b.lower), min(a.upper,b.upper))
==(a::VersionInterval, b::VersionInterval) = a.lower == b.lower && a.upper == b.upper
hash(i::VersionInterval, h::UInt) = hash((i.lower, i.upper), h + (0x0f870a92db508386 % UInt))

function normalize!(ivals::Vector{VersionInterval})
# VersionSet internal normalization:
# removes empty intervals and fuses intervals without gaps
# e.g.:
# [0.0.0,1.0.0) ∪ [1.0.0,1.5.0) ∪ [1.6.0,1.6.0) ∪ [2.0.0,∞)
# becomes:
# [0.0.0,1.5.0) ∪ [2.0.0,∞)
# (still assumes that lower bounds are sorted, and intervals do
# not overlap)
l = length(ivals)
l == 0 && return ivals

lo, up, k0 = ivals[1].lower, ivals[1].upper, 1
fusing = false
for k = 2:l
lo1, up1 = ivals[k].lower, ivals[k].upper
if lo1 == up
up = up1
fusing = true
continue
end
if lo < up
# The only purpose of the "fusing" check is to avoid
# extra allocations
ivals[k0] = fusing ? VersionInterval(lo, up) : ivals[k-1]
k0 += 1
end
fusing = false
lo, up = lo1, up1
end
if lo < up
ivals[k0] = fusing ? VersionInterval(lo, up) : ivals[l]
k0 += 1
end
resize!(ivals, k0 - 1)
return ivals
end

struct VersionSet
intervals::Vector{VersionInterval}
VersionSet(intervals::Vector{VersionInterval}) = new(normalize!(intervals))
# copy is defined inside the struct block to call `new` directly
# without going through `normalize!`
Base.copy(vset::VersionSet) = new(copy(vset.intervals))
end
function VersionSet(versions::Vector{VersionNumber})
intervals = VersionInterval[]
if isempty(versions)
push!(intervals, VersionInterval())
else
isodd(length(versions)) && push!(versions, typemax(VersionNumber))
while !isempty(versions)
push!(intervals, VersionInterval(shift!(versions), shift!(versions)))
end
end
VersionSet(intervals)
end
VersionSet(versions::VersionNumber...) = VersionSet(VersionNumber[versions...])

const empty_versionset = VersionSet(VersionInterval[])

# Windows console doesn't like Unicode
const _empty_symbol = @static iswindows() ? "empty" : ""
const _union_symbol = @static iswindows() ? " or " : ""
show(io::IO, s::VersionSet) = isempty(s) ? print(io, _empty_symbol) :
join(io, s.intervals, _union_symbol)
isempty(s::VersionSet) = all(isempty, s.intervals)
in(v::VersionNumber, s::VersionSet) = any(i->in(v,i), s.intervals)
function intersect(A::VersionSet, B::VersionSet)
(isempty(A) || isempty(B)) && return copy(empty_versionset)
ivals = [intersect(a,b) for a in A.intervals for b in B.intervals]
sort!(ivals, by=i->i.lower)
VersionSet(ivals)
end

union(A::VersionSet, B::VersionSet) = union!(copy(A), B)
function union!(A::VersionSet, B::VersionSet)
A == B && return A
ivals = A.intervals
for intB in B.intervals
lB, uB = intB.lower, intB.upper
k0 = findfirst(i->(i.upper > lB), ivals)
if k0 == 0
push!(ivals, intB)
continue
end
lB = min(lB, ivals[k0].lower)
for k1 = k0:length(ivals)
intA = ivals[k1]
if uB < intA.lower
splice!(ivals, k0:(k1-1), (VersionInterval(lB, uB),))
break
elseif uB intA || k1 == length(ivals)
splice!(ivals, k0:k1, (VersionInterval(lB, max(uB, intA.upper)),))
break
end
end
end
normalize!(ivals)
return A
end

==(A::VersionSet, B::VersionSet) = A.intervals == B.intervals
hash(s::VersionSet, h::UInt) = hash(s.intervals, h + (0x2fd2ca6efa023f44 % UInt))
deepcopy_internal(vs::VersionSet, ::ObjectIdDict) = copy(vs)

end # module
7 changes: 4 additions & 3 deletions bin/loadmeta.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ using Base: thispatch, thisminor, nextpatch, nextminor
using Base.LinAlg: checksquare
using Base.Random: UUID
using Pkg3.Types
using Pkg3.Types: uuid_package, uuid_registry, uuid5

import Pkg3.Pkg2
import Pkg2.Reqs: Reqs, Requirement
import Pkg2.Types: VersionInterval
include("Pkg2/Pkg2.jl")
import .Pkg2.Reqs: Reqs, Requirement
import .Pkg2.Types: VersionInterval

## Loading data into various data structures ##

Expand Down

0 comments on commit 6370caf

Please sign in to comment.