-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
/
Copy pathreqs.jl
145 lines (129 loc) · 4.85 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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# This file is a part of Julia. License is MIT: https://julialang.org/license
module Reqs
import Base: ==
import ...Pkg.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
function Requirement(package::AbstractString, versions::VersionSet, system::Vector{AbstractString}=AbstractString[])
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
==(a::Line, b::Line) = a.content == b.content
hash(s::Line, h::UInt) = hash(s.content, h + (0x3f5a631add21cb1a % UInt))
# general machinery for parsing REQUIRE files
function read(readable::Vector{<:AbstractString})
lines = Line[]
for line in readable
line = chomp(line)
push!(lines, ismatch(r"^\s*(?:#|$)", line) ? Comment(line) : Requirement(line))
end
return lines
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[]
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!(collect(keys(reqs)), by=Unicode.lowercase)
println(io, Requirement(pkg, reqs[pkg]).content)
end
end
write(file::AbstractString, 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
if Sys.iswindows(); applies |= ("windows" in line.system); end
if Sys.isunix(); applies |= ("unix" in line.system); end
if Sys.isapple(); applies |= ("osx" in line.system); end
if Sys.islinux(); applies |= ("linux" in line.system); end
if Sys.isbsd(); applies |= ("bsd" in line.system); end
if Sys.iswindows(); applies &= !("!windows" in line.system); end
if Sys.isunix(); applies &= !("!unix" in line.system); end
if Sys.isapple(); applies &= !("!osx" in line.system); end
if Sys.islinux(); applies &= !("!linux" in line.system); end
if Sys.isbsd(); applies &= !("!bsd" in line.system); end
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))
function dependents(packagename::AbstractString)
pkgs = AbstractString[]
cd(Pkg.dir()) do
for (pkg,latest) in Pkg.Read.latest()
if haskey(latest.requires, packagename)
push!(pkgs, pkg)
end
end
end
pkgs
end
# add & rm – edit the content a requires file
function add(lines::Vector{Line}, pkg::AbstractString, 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::AbstractString) = filter(lines) do line
isa(line,Comment) || line.package != pkg
end
end # module