Files
textmate/bin/upload
2013-05-02 16:13:33 +07:00

108 lines
3.6 KiB
Ruby
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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