Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move development related functions to PkgDev package #13387

Merged
merged 4 commits into from
Oct 13, 2015
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
28 changes: 0 additions & 28 deletions base/docs/helpdb.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11648,13 +11648,6 @@ Initialize `Pkg.dir()` as a package directory. This will be done automatically w
"""
Pkg.init()

doc"""
publish()

For each new package version tagged in `METADATA` not already published, make sure that the tagged package commits have been pushed to the repo at the registered URL for the package and if they all have, open a pull request to `METADATA`.
"""
Pkg.publish()

doc"""
pin(pkg)

Expand Down Expand Up @@ -11690,13 +11683,6 @@ Returns the version numbers available for package `pkg`.
"""
Pkg.available(pkg)

doc"""
register(pkg, [url])

Register `pkg` at the git URL `url`, defaulting to the configured origin URL of the git repo `Pkg.dir(pkg)`.
"""
Pkg.register(pkg, url=?)

doc"""
rm(pkg)

Expand Down Expand Up @@ -11762,13 +11748,6 @@ Add a requirement entry for `pkg` to `Pkg.dir("REQUIRE")` and call `Pkg.resolve(
"""
Pkg.add(pkg, vers...)

doc"""
tag(pkg, [ver, [commit]])

Tag `commit` as version `ver` of package `pkg` and create a version entry in `METADATA`. If not provided, `commit` defaults to the current commit of the `pkg` repo. If `ver` is one of the symbols `:patch`, `:minor`, `:major` the next patch, minor or major version is used. If `ver` is not provided, it defaults to `:patch`.
"""
Pkg.tag(pkg)

doc"""
test()

Expand All @@ -11783,13 +11762,6 @@ Run the tests for each package in `pkgs` ensuring that each package's test depen
"""
Pkg.test(pkgs...)

doc"""
generate(pkg,license)

Generate a new package named `pkg` with one of these license keys: `"MIT"`, `"BSD"` or `"ASL"`. If you want to make a package with a different license, you can edit it afterwards. Generate creates a git repo at `Pkg.dir(pkg)` for the package and inside it `LICENSE.md`, `README.md`, `REQUIRE`, the julia entrypoint `$pkg/src/$pkg.jl`, and Travis and AppVeyor CI configuration files `.travis.yml` and `appveyor.yml`.
"""
Pkg.generate(pkg,license)

doc"""
dir() -> AbstractString

Expand Down
26 changes: 3 additions & 23 deletions base/pkg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

module Pkg

export Git, Dir, GitHub, Types, Reqs, Cache, Read, Query, Resolve, Write, Generate, Entry, Git
export Git, Dir, Types, Reqs, Cache, Read, Query, Resolve, Write, Entry, Git
export dir, init, rm, add, available, installed, status, clone, checkout,
update, resolve, register, tag, publish, generate, test,
build, free, pin, PkgError
update, resolve, test, build, free, pin, PkgError

const DEFAULT_META = "https://github.com/JuliaLang/METADATA.jl"
const META_BRANCH = "metadata-v2"
Expand All @@ -14,7 +13,7 @@ type PkgError <: Exception
msg::AbstractString
end

for file in split("dir github types reqs cache read query resolve write generate entry git")
for file in split("dir types reqs cache read query resolve write entry git")
include("pkg/$file.jl")
end
const cd = Dir.cd
Expand Down Expand Up @@ -49,28 +48,9 @@ pin(pkg::AbstractString, ver::VersionNumber) = cd(Entry.pin,pkg,ver)
update() = cd(Entry.update,Dir.getmetabranch())
resolve() = cd(Entry.resolve)

register(pkg::AbstractString) = cd(Entry.register,pkg)
register(pkg::AbstractString, url::AbstractString) = cd(Entry.register,pkg,url)

tag(pkg::AbstractString, sym::Symbol=:patch) = cd(Entry.tag,pkg,sym)
tag(pkg::AbstractString, sym::Symbol, commit::AbstractString) = cd(Entry.tag,pkg,sym,false,commit)

tag(pkg::AbstractString, ver::VersionNumber; force::Bool=false) = cd(Entry.tag,pkg,ver,force)
tag(pkg::AbstractString, ver::VersionNumber, commit::AbstractString; force::Bool=false) =
cd(Entry.tag,pkg,ver,force,commit)

submit(pkg::AbstractString) = cd(Entry.submit,pkg)
submit(pkg::AbstractString, commit::AbstractString) = cd(Entry.submit,pkg,commit)

publish() = cd(Entry.publish,Dir.getmetabranch())

build() = cd(Entry.build)
build(pkgs::AbstractString...) = cd(Entry.build,[pkgs...])

generate(pkg::AbstractString, license::AbstractString; force::Bool=false, authors::Union{AbstractString,Array} = [], config::Dict=Dict()) =
cd(Generate.package,pkg,license,force=force,authors=authors,config=config)


test(;coverage::Bool=false) = cd(Entry.test; coverage=coverage)
test(pkgs::AbstractString...; coverage::Bool=false) = cd(Entry.test,AbstractString[pkgs...]; coverage=coverage)

Expand Down
261 changes: 1 addition & 260 deletions base/pkg/entry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Entry

import Base: thispatch, nextpatch, nextminor, nextmajor, check_new_version
import ..Reqs, ..Read, ..Query, ..Resolve, ..Cache, ..Write, ..GitHub, ..Dir
import ..Reqs, ..Read, ..Query, ..Resolve, ..Cache, ..Write, ..Dir
import ...LibGit2
importall ...LibGit2
import ...Pkg.PkgError
Expand Down Expand Up @@ -371,96 +371,6 @@ function update(branch::AbstractString)
updatehook(sort!(collect(keys(installed()))))
end

function pull_request(dir::AbstractString, commit::AbstractString="", url::AbstractString="")
with(GitRepo, dir) do repo
if isempty(commit)
commit = string(LibGit2.head_oid(repo))
else
!LibGit2.iscommit(commit, repo) && throw(PkgError("Cannot find pull commit: $commit"))
end
if isempty(url)
url = LibGit2.getconfig(repo, "remote.origin.url", "")
end

m = match(LibGit2.GITHUB_REGEX, url)
m === nothing && throw(PkgError("not a GitHub repo URL, can't make a pull request: $url"))
owner, owner_repo = m.captures[2:3]
user = GitHub.user()
info("Forking $owner/$owner_repo to $user")
response = GitHub.fork(owner,owner_repo)
fork = response["ssh_url"]
branch = "pull-request/$(commit[1:8])"
info("Pushing changes as branch $branch")
refspecs = ["HEAD:refs/heads/$branch"] # workaround for $commit:refs/heads/$branch
LibGit2.push(repo, remoteurl=fork, refspecs=refspecs)
pr_url = "$(response["html_url"])/compare/$branch"
info("To create a pull-request, open:\n\n $pr_url\n")
end
end

function submit(pkg::AbstractString, commit::AbstractString="")
urlpath = joinpath("METADATA",pkg,"url")
url = ispath(urlpath) ? readchomp(urlpath) : ""
pull_request(pkg, commit, url)
end

function publish(branch::AbstractString)
tags = Dict{ByteString,Vector{ASCIIString}}()

with(GitRepo, "METADATA") do repo
LibGit2.branch(repo) == branch ||
throw(PkgError("METADATA must be on $branch to publish changes"))
LibGit2.fetch(repo)

ahead_remote, ahead_local = LibGit2.revcount(repo, "origin/$branch", branch)
ahead_remote > 0 && throw(PkgError("METADATA is behind origin/$branch – run `Pkg.update()` before publishing"))
ahead_local == 0 && throw(PkgError("There are no METADATA changes to publish"))

# get changed files
for path in LibGit2.diff_files(repo, "origin/$branch", LibGit2.Consts.HEAD_FILE)
m = match(r"^(.+?)/versions/([^/]+)/sha1$", path)
m !== nothing && ismatch(Base.VERSION_REGEX, m.captures[2]) || continue
pkg, ver = m.captures; ver = convert(VersionNumber,ver)
sha1 = readchomp(joinpath("METADATA",path))
old = LibGit2.cat(repo, LibGit2.GitBlob, "origin/$branch:$path")
old !== nothing && old != sha1 && throw(PkgError("$pkg v$ver SHA1 changed in METADATA – refusing to publish"))
with(GitRepo, pkg) do pkg_repo
tag_name = "v$ver"
tag_commit = LibGit2.revparseid(pkg_repo, "$(tag_name)^{commit}")
LibGit2.iszero(tag_commit) || string(tag_commit) == sha1 || return false
haskey(tags,pkg) || (tags[pkg] = ASCIIString[])
push!(tags[pkg], tag_name)
return true
end || throw(PkgError("$pkg v$ver is incorrectly tagged – $sha1 expected"))
end
isempty(tags) && info("No new package versions to publish")
info("Validating METADATA")
check_metadata(Set(keys(tags)))
end

for pkg in sort!(collect(keys(tags)))
with(GitRepo, pkg) do pkg_repo
forced = ASCIIString[]
unforced = ASCIIString[]
for tag in tags[pkg]
ver = convert(VersionNumber,tag)
push!(isrewritable(ver) ? forced : unforced, tag)
end
if !isempty(forced)
info("Pushing $pkg temporary tags: ", join(forced,", "))
LibGit2.push(pkg_repo, remote="origin", force=true,
refspecs=["refs/tags/$tag:refs/tags/$tag" for tag in forced])
end
if !isempty(unforced)
info("Pushing $pkg permanent tags: ", join(unforced,", "))
LibGit2.push(pkg_repo, remote="origin",
refspecs=["refs/tags/$tag:refs/tags/$tag" for tag in unforced])
end
end
end
info("Submitting METADATA changes")
pull_request("METADATA")
end

function resolve(
reqs :: Dict = Reqs.parse("REQUIRE"),
Expand Down Expand Up @@ -547,175 +457,6 @@ function resolve(
build(map(x->x[1], filter(x -> x[2][2] !== nothing, changes)))
end

function write_tag_metadata(repo::GitRepo, pkg::AbstractString, ver::VersionNumber, commit::AbstractString, force::Bool=false)
content = with(GitRepo,pkg) do pkg_repo
LibGit2.cat(pkg_repo, LibGit2.GitBlob, "$commit:REQUIRE")
end
reqs = content !== nothing ? Reqs.read(split(content, '\n', keep=false)) : Reqs.Line[]
cd("METADATA") do
d = joinpath(pkg,"versions",string(ver))
mkpath(d)
sha1file = joinpath(d,"sha1")
if !force && ispath(sha1file)
current = readchomp(sha1file)
current == commit ||
throw(PkgError("$pkg v$ver is already registered as $current, bailing"))
end
open(io->println(io,commit), sha1file, "w")
LibGit2.add!(repo, sha1file)
reqsfile = joinpath(d,"requires")
if isempty(reqs)
ispath(reqsfile) && LibGit2.remove!(repo, reqsfile)
else
Reqs.write(reqsfile,reqs)
LibGit2.add!(repo, reqsfile)
end
end
return nothing
end

function register(pkg::AbstractString, url::AbstractString)
ispath(pkg,".git") || throw(PkgError("$pkg is not a git repo"))
isfile("METADATA",pkg,"url") && throw(PkgError("$pkg already registered"))
LibGit2.transact(GitRepo("METADATA")) do repo
# Get versions from package repo
versions = with(GitRepo, pkg) do pkg_repo
tags = filter(t->startswith(t,"v"), LibGit2.tag_list(pkg_repo))
filter!(tag->ismatch(Base.VERSION_REGEX,tag), tags)
[
convert(VersionNumber,tag) => string(LibGit2.revparseid(pkg_repo, "$tag^{commit}"))
for tag in tags
]
end
# Register package url in METADATA
cd("METADATA") do
info("Registering $pkg at $url")
mkdir(pkg)
path = joinpath(pkg,"url")
open(io->println(io,url), path, "w")
LibGit2.add!(repo, path)
end
# Register package version in METADATA
vers = sort!(collect(keys(versions)))
for ver in vers
info("Tagging $pkg v$ver")
write_tag_metadata(repo, pkg,ver,versions[ver])
end
# Commit changes in METADATA
if LibGit2.isdirty(repo)
info("Committing METADATA for $pkg")
msg = "Register $pkg"
if !isempty(versions)
msg *= ": $(join(map(v->"v$v", vers),", "))"
end
LibGit2.commit(repo, msg)
else
info("No METADATA changes to commit")
end
end
return
end

function register(pkg::AbstractString)
url = ""
try
url = LibGit2.getconfig(pkg, "remote.origin.url", "")
catch err
throw(PkgError("$pkg: $err"))
end
!isempty(url) || throw(PkgError("$pkg: no URL configured"))
register(pkg, GitHub.normalize_url(url))
end

function isrewritable(v::VersionNumber)
thispatch(v)==v"0" ||
length(v.prerelease)==1 && isempty(v.prerelease[1]) ||
length(v.build)==1 && isempty(v.build[1])
end

nextbump(v::VersionNumber) = isrewritable(v) ? v : nextpatch(v)

function tag(pkg::AbstractString, ver::Union{Symbol,VersionNumber}, force::Bool=false, commitish::AbstractString="HEAD")
ispath(pkg,".git") || throw(PkgError("$pkg is not a git repo"))
with(GitRepo,"METADATA") do repo
LibGit2.isdirty(repo, pkg) && throw(PkgError("METADATA/$pkg is dirty – commit or stash changes to tag"))
end
with(GitRepo,pkg) do repo
LibGit2.isdirty(repo) && throw(PkgError("$pkg is dirty – commit or stash changes to tag"))
commit = string(LibGit2.revparseid(repo, commitish))
registered = isfile("METADATA",pkg,"url")

if !force
if registered
avail = Read.available(pkg)
existing = VersionNumber[keys(Read.available(pkg))...]
ancestors = filter(v->LibGit2.is_ancestor_of(avail[v].sha1, commit, repo), existing)
else
tags = filter(t->startswith(t,"v"), LibGit2.tag_list(repo))
filter!(tag->ismatch(Base.VERSION_REGEX,tag), tags)
existing = VersionNumber[tags...]
filter!(tags) do tag
sha1 = string(LibGit2.revparseid(repo, "$tag^{commit}"))
LibGit2.is_ancestor_of(sha1, commit, repo)
end
ancestors = VersionNumber[tags...]
end
sort!(existing)
if isa(ver,Symbol)
prv = isempty(existing) ? v"0" :
isempty(ancestors) ? maximum(existing) : maximum(ancestors)
ver = (ver == :bump ) ? nextbump(prv) :
(ver == :patch) ? nextpatch(prv) :
(ver == :minor) ? nextminor(prv) :
(ver == :major) ? nextmajor(prv) :
throw(PkgError("invalid version selector: $ver"))
end
isrewritable(ver) && filter!(v->v!=ver,existing)
check_new_version(existing,ver)
end
# TODO: check that SHA1 isn't the same as another version
info("Tagging $pkg v$ver")
LibGit2.tag_create(repo, "v$ver", commit,
msg=(!isrewritable(ver) ? "$pkg v$ver [$(commit[1:10])]" : ""),
force=(force || isrewritable(ver)) )
registered || return
try
LibGit2.transact(GitRepo("METADATA")) do repo
write_tag_metadata(repo, pkg, ver, commit, force)
if LibGit2.isdirty(repo)
info("Committing METADATA for $pkg")
LibGit2.commit(repo, "Tag $pkg v$ver")
else
info("No METADATA changes to commit")
end
end
catch
LibGit2.tag_delete(repo, "v$ver")
rethrow()
end
end
return
end

function check_metadata(pkgs::Set{ByteString} = Set{ByteString}())
avail = Read.available()
deps, conflicts = Query.dependencies(avail)

for (dp,dv) in deps, (v,a) in dv, p in keys(a.requires)
haskey(deps, p) || throw(PkgError("package $dp v$v requires a non-registered package: $p"))
end

problematic = Resolve.sanity_check(deps, pkgs)
if !isempty(problematic)
msg = "packages with unsatisfiable requirements found:\n"
for (p, vn, rp) in problematic
msg *= " $p v$vn – no valid versions exist for package $rp\n"
end
throw(PkgError(msg))
end
return
end

function warnbanner(msg...; label="[ WARNING ]", prefix="")
cols = Base.tty_size()[2]
warn(prefix="", Base.cpad(label,cols,"="))
Expand Down
Loading