mirror of
https://github.com/textmate/textmate.git
synced 2026-01-13 16:57:56 -05:00
118 lines
4.0 KiB
Ruby
Executable File
118 lines
4.0 KiB
Ruby
Executable File
#!/System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/ruby -w
|
||
# == Synopsis
|
||
#
|
||
# upload [-k «keyfile»] [-d «destination»] [-m «json»] «file»
|
||
#
|
||
# == Usage
|
||
#
|
||
# --help:
|
||
# show help.
|
||
#
|
||
# --keyfile/-k:
|
||
# Keyfile used for signing.
|
||
#
|
||
# --destination/-d:
|
||
# Which GitHub ‘«user»/«repository»’ we should upload to.
|
||
#
|
||
# --merge/-m:
|
||
# JSON that should be placed in the result dictionary.
|
||
#
|
||
# --description/-s:
|
||
# Optional description.
|
||
#
|
||
require 'getoptlong'
|
||
require "rubygems"
|
||
require "net/netrc"
|
||
require "json"
|
||
require 'base64'
|
||
require 'openssl'
|
||
require 'digest/sha1'
|
||
|
||
def sign_file(path, keyfile, password)
|
||
# %x{openssl dgst -dss1 -sign '#{keyfile}' -passin 'pass:#{password}' '#{path}'|openssl enc -base64}.chomp
|
||
|
||
key = OpenSSL::PKey::DSA.new(File.read(keyfile), password) or abort "*** error reading keyfile: ‘#{keyfile}’."
|
||
digest = Digest::SHA1.digest(File.read(path))
|
||
signature = key.syssign(digest)
|
||
Base64.encode64(signature).gsub("\n", '')
|
||
end
|
||
|
||
def create_release(path, repository, tag, description, content_type)
|
||
name = tag.sub(/^v(.*?)-(.*?)\.(.*)$/, 'TextMate \1 (\2 \3)')
|
||
basename = File::basename(path)
|
||
payload = { 'name' => name, 'tag_name' => tag, 'draft' => false, 'prerelease' => true }
|
||
payload['body'] = description unless description.nil?
|
||
open("|curl -snd '#{payload.to_json}' https://api.github.com/repos/#{repository}/releases") do |response|
|
||
github = JSON.parse(response.read)
|
||
|
||
if github.include?('errors')
|
||
err = github['errors'].first
|
||
if err['code'] == 'already_exists' && err['field'] == 'tag_name'
|
||
open("|curl -sn https://api.github.com/repos/#{repository}/releases") do |io|
|
||
github = JSON.parse(io.read)
|
||
github = github.find { |e| e['tag_name'] == tag }
|
||
STDERR << "Upload to existing release: #{github['html_url']}\n"
|
||
end
|
||
else
|
||
abort "GitHub error: #{github['errors'].inspect} for #{repository}" if github.include?('errors')
|
||
end
|
||
end
|
||
|
||
if url = github['upload_url']
|
||
url.sub!(/\{\?.*?\}/, '')
|
||
upload_url = "|curl -nH'Content-Type: #{content_type}' --data-binary @'#{path}' '#{url}?name=#{basename}'"
|
||
open(upload_url) do |io|
|
||
res = JSON.parse(io.read)
|
||
return "https://github.com/#{repository}/releases/download/#{tag}/#{basename}" if res.include?('url')
|
||
STDERR << "Unexpected response (asset): #{res.inspect}\n"
|
||
end
|
||
else
|
||
STDERR << "Unexpected response (release): #{github.inspect}\n"
|
||
end
|
||
open("|curl -snX DELETE #{github['url']}") { |io| STDERR << "Removing release: #{github['url']}\n" }
|
||
end
|
||
abort
|
||
end
|
||
|
||
if __FILE__ == $PROGRAM_NAME
|
||
opts = GetoptLong.new(
|
||
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
||
[ '--keyfile', '-k', GetoptLong::REQUIRED_ARGUMENT ],
|
||
[ '--destination', '-d', GetoptLong::REQUIRED_ARGUMENT ],
|
||
[ '--tag', '-t', GetoptLong::REQUIRED_ARGUMENT ],
|
||
[ '--merge', '-m', GetoptLong::REQUIRED_ARGUMENT ],
|
||
[ '--description', '-s', GetoptLong::REQUIRED_ARGUMENT ]
|
||
)
|
||
|
||
keyfile = nil
|
||
destination = 'textmate/textmate'
|
||
tag = nil
|
||
base_info = { }
|
||
description = nil
|
||
netinfo = Net::Netrc.locate("sign.textmate.org") or abort "*** missing passphrase in ~/.netrc."
|
||
|
||
opts.each do |opt, arg|
|
||
case opt
|
||
when '--help' then RDoc::usage
|
||
when '--keyfile' then keyfile = arg
|
||
when '--destination' then destination = arg
|
||
when '--tag' then tag = arg
|
||
when '--merge' then base_info = JSON.parse(arg)
|
||
when '--description' then description = arg
|
||
end
|
||
end
|
||
|
||
abort 'No signing key provided' if keyfile.nil?
|
||
abort "No tag specified" if tag.nil?
|
||
|
||
if path = ARGV.shift
|
||
signature = sign_file(path, keyfile, netinfo.password)
|
||
info = base_info.merge({
|
||
'url' => create_release(path, destination, tag, description, 'application/x-bzip2'),
|
||
'signature' => signature,
|
||
'signee' => netinfo.login
|
||
})
|
||
STDOUT << info.to_json
|
||
end
|
||
end
|