forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
reqs.jl
119 lines (106 loc) · 3.87 KB
/
reqs.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
module Reqs
using ..Types
# representing lines of REQUIRE files
abstract Line
immutable Comment <: Line
content::String
end
immutable Requirement <: Line
content::String
package::String
versions::VersionSet
system::Vector{String}
function Requirement(content::String)
fields = split(replace(content, r"#.*$", ""))
system = String[]
while !isempty(fields) && fields[1][1] == '@'
push!(system,shift!(fields)[2:end])
end
isempty(fields) && error("invalid requires entry: $content")
package = shift!(fields)
all(field->ismatch(Base.VERSION_REGEX, field), fields) ||
error("invalid requires entry for $package: $content")
versions = [ convert(VersionNumber, field) for field in fields ]
issorted(versions) || error("invalid requires entry for $package: $content")
new(content, package, VersionSet(versions), system)
end
function Requirement(package::String, versions::VersionSet, system::Vector{String}=String[])
content = ""
for os in system
content *= "@$os "
end
content *= package
if versions != VersionSet()
for ival in versions.intervals
(content *= " $(ival.lower)")
ival.upper < typemax(VersionNumber) &&
(content *= " $(ival.upper)")
end
end
new(content, package, versions, system)
end
end
# TODO: shouldn't be neccessary #4648
Base.isequal(a::Line, b::Line) = (a.content == b.content)
# general machinery for parsing REQUIRE files
function read(readable::Union(IO,Base.AbstractCmd))
lines = Line[]
for line in eachline(readable)
line = chomp(line)
push!(lines, ismatch(r"^\s*(?:#|$)", line) ? Comment(line) : Requirement(line))
end
return lines
end
read(file::String) = isfile(file) ? open(read,file) : Line[]
function write(io::IO, lines::Vector{Line})
for line in lines
println(io, line.content)
end
end
function write(io::IO, reqs::Requires)
for pkg in sort!([keys(reqs)...], by=lowercase)
println(io, Requirement(pkg, reqs[pkg]).content)
end
end
write(file::String, r::Union(Vector{Line},Requires)) = open(io->write(io,r), file, "w")
function parse(lines::Vector{Line})
reqs = Requires()
for line in lines
if isa(line,Requirement)
if !isempty(line.system)
applies = false
@windows_only applies |= ("windows" in line.system)
@unix_only applies |= ("unix" in line.system)
@osx_only applies |= ("osx" in line.system)
@linux_only applies |= ("linux" in line.system)
@windows_only applies &= !("!windows" in line.system)
@unix_only applies &= !("!unix" in line.system)
@osx_only applies &= !("!osx" in line.system)
@linux_only applies &= !("!linux" in line.system)
applies || continue
end
reqs[line.package] = haskey(reqs, line.package) ?
intersect(reqs[line.package], line.versions) : line.versions
end
end
return reqs
end
parse(x) = parse(read(x))
# add & rm – edit the content a requires file
function add(lines::Vector{Line}, pkg::String, versions::VersionSet=VersionSet())
v = VersionSet[]
filtered = filter(lines) do line
if !isa(line,Comment) && line.package == pkg && isempty(line.system)
push!(v, line.versions)
return false
end
return true
end
length(v) == 1 && v[1] == intersect(v[1],versions) && return copy(lines)
versions = reduce(intersect, versions, v)
push!(filtered, Requirement(pkg, versions))
end
rm(lines::Vector{Line}, pkg::String) = filter(lines) do line
isa(line,Comment) || line.package != pkg
end
end # module