mirror of
https://github.com/textmate/textmate.git
synced 2026-01-20 04:08:04 -05:00
108 lines
3.6 KiB
Ruby
Executable File
108 lines
3.6 KiB
Ruby
Executable File
#!/usr/bin/env ruby -wKU
|
||
# == 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 aws_upload(path, url, key, acl, filename, content_type, access_key, policy, signature)
|
||
rc = %x{curl -sw'%{http_code}' --show-error -o/dev/null \
|
||
-F "key=#{key}" \
|
||
-F "acl=#{acl}" \
|
||
-F "success_action_status=201" \
|
||
-F "Filename=#{filename}" \
|
||
-F "Content-Type=#{content_type}" \
|
||
-F "AWSAccessKeyId=#{access_key}" \
|
||
-F "Policy=#{policy}" \
|
||
-F "Signature=#{signature}" \
|
||
-F "file=@#{path}" \
|
||
#{url}
|
||
}
|
||
STDERR << "*** error uploading to #{url} (#{rc})\n" unless rc == '201'
|
||
return rc == '201'
|
||
end
|
||
|
||
def create_download(path, repository, description, content_type)
|
||
payload = { 'name' => File::basename(path), 'size' => File::size(path), 'content_type' => content_type || 'application/octet-stream' }
|
||
payload['description'] = description unless description.nil?
|
||
|
||
open("|curl -snd '#{payload.to_json}' https://api.github.com/repos/#{repository}/downloads") do |io|
|
||
github = JSON.parse(io.read)
|
||
abort "github error: #{github['errors'].inspect} for #{repository}" if github.include?('errors')
|
||
abort "github unexpected response: #{github.inspect} for #{repository}" unless github.include?('html_url')
|
||
return github['html_url'] if aws_upload(path, github['s3_url'], github['path'], github['acl'], payload['name'], payload['content_type'], github['accesskeyid'], github['policy'], github['signature'])
|
||
open("|curl -snX DELETE https://api.github.com/repos/#{repository}/downloads/#{github['id']}") { |io| STDERR << "Removing partial upload\n" }
|
||
abort
|
||
end
|
||
nil
|
||
end
|
||
|
||
if __FILE__ == $PROGRAM_NAME
|
||
opts = GetoptLong.new(
|
||
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
||
[ '--keyfile', '-k', GetoptLong::REQUIRED_ARGUMENT ],
|
||
[ '--destination', '-d', GetoptLong::REQUIRED_ARGUMENT ],
|
||
[ '--merge', '-m', GetoptLong::REQUIRED_ARGUMENT ],
|
||
[ '--description', '-s', GetoptLong::REQUIRED_ARGUMENT ]
|
||
)
|
||
|
||
keyfile = nil
|
||
destination = 'textmate/textmate'
|
||
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 '--merge' then base_info = JSON.parse(arg)
|
||
when '--description' then description = arg
|
||
end
|
||
end
|
||
|
||
abort 'No signing key provided' if keyfile.nil?
|
||
|
||
if path = ARGV.shift
|
||
info = base_info.merge({
|
||
'url' => create_download(path, destination, description, 'application/x-bzip2'),
|
||
'signature' => sign_file(path, keyfile, netinfo.password),
|
||
'signee' => netinfo.login
|
||
})
|
||
STDOUT << info.to_json
|
||
end
|
||
end
|