| # require |
| require 'rubygems' |
| |
| #### INLINE: fixed version of https://github.com/github/upload #### |
| |
| require 'tempfile' |
| require 'nokogiri' |
| require 'httpclient' |
| require 'stringio' |
| require 'json' |
| require 'faster_xml_simple' |
| |
| module Net |
| module GitHub |
| class Upload |
| VERSION = '0.0.5' |
| def initialize params=nil |
| @login = params[:login] |
| @token = params[:token] |
| |
| if @login.empty? or @token.empty? |
| raise "login or token is empty" |
| end |
| end |
| |
| def upload info |
| unless info[:repos] |
| raise "required repository name" |
| end |
| info[:repos] = @login + '/' + info[:repos] unless info[:repos].include? '/' |
| |
| if info[:file] |
| file = info[:file] |
| unless File.exist?(file) && File.readable?(file) |
| raise "file does not exsits or readable" |
| end |
| info[:name] ||= File.basename(file) |
| end |
| unless info[:file] || info[:data] |
| raise "required file or data parameter to upload" |
| end |
| |
| unless info[:name] |
| raise "required name parameter for filename with data parameter" |
| end |
| |
| if info[:replace] |
| list_files(info[:repos]).each { |obj| |
| next unless obj[:name] == info[:name] |
| delete info[:repos], obj[:id] |
| } |
| elsif list_files(info[:repos]).any?{|obj| obj[:name] == info[:name]} |
| raise "file '#{info[:name]}' is already uploaded. please try different name" |
| end |
| |
| info[:content_type] ||= 'application/octet-stream' |
| stat = HTTPClient.post("https://github.com/#{info[:repos]}/downloads", { |
| "file_size" => info[:file] ? File.stat(info[:file]).size : info[:data].size, |
| "content_type" => info[:content_type], |
| "file_name" => info[:name], |
| "description" => info[:description] || '', |
| "login" => @login, |
| "token" => @token |
| }) |
| |
| unless stat.code == 200 |
| raise "Failed to post file info" |
| end |
| |
| upload_info = JSON.parse(stat.content) |
| if info[:file] |
| f = File.open(info[:file], 'rb') |
| else |
| f = Tempfile.open('net-github-upload') |
| f << info[:data] |
| f.flush |
| end |
| stat = HTTPClient.post("http://github.s3.amazonaws.com/", [ |
| ['Filename', info[:name]], |
| ['policy', upload_info['policy']], |
| ['success_action_status', 201], |
| ['key', upload_info['path']], |
| ['AWSAccessKeyId', upload_info['accesskeyid']], |
| ['Content-Type', upload_info['content_type'] || 'application/octet-stream'], |
| ['signature', upload_info['signature']], |
| ['acl', upload_info['acl']], |
| ['file', f] |
| ]) |
| f.close |
| |
| if stat.code == 201 |
| return FasterXmlSimple.xml_in(stat.content)['PostResponse']['Location'] |
| else |
| raise 'Failed to upload' + extract_error_message(stat) |
| end |
| end |
| |
| def replace info |
| upload info.merge( :replace => true ) |
| end |
| |
| def delete_all repos |
| unless repos |
| raise "required repository name" |
| end |
| repos = @login + '/' + repos unless repos.include? '/' |
| list_files(repos).each { |obj| |
| delete repos, obj[:id] |
| } |
| end |
| |
| private |
| |
| def extract_error_message(stat) |
| # @see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/ErrorResponses.html |
| error = FasterXmlSimple.xml_in(stat.content)['Error'] |
| " due to #{error['Code']} (#{error['Message']})" |
| rescue |
| '' |
| end |
| |
| def delete repos, id |
| HTTPClient.post("https://github.com/#{repos}/downloads/#{id.gsub( "download_", '')}", { |
| "_method" => "delete", |
| "login" => @login, |
| "token" => @token |
| }) |
| end |
| |
| def list_files repos |
| raise "required repository name" unless repos |
| res = HTTPClient.get_content("https://github.com/#{repos}/downloads", { |
| "login" => @login, |
| "token" => @token |
| }) |
| Nokogiri::HTML(res).xpath('id("manual_downloads")/li').map do |fileinfo| |
| obj = { |
| :description => fileinfo.at_xpath('descendant::h4').text, |
| :date => fileinfo.at_xpath('descendant::p/time').attribute('title').text, |
| :size => fileinfo.at_xpath('descendant::p/strong').text, |
| :id => /\d+$/.match(fileinfo.at_xpath('a').attribute('href').text)[0] |
| } |
| anchor = fileinfo.at_xpath('descendant::h4/a') |
| obj[:link] = anchor.attribute('href').text |
| obj[:name] = anchor.text |
| obj |
| end |
| end |
| end |
| end |
| end |
| |
| #### END INLINE #### |
| |
| # setup |
| login = `git config github.user`.chomp # your login for github |
| token = `git config github.token`.chomp # your token for github |
| repos = 'KentBeck/junit' # your repos name (like 'taberareloo') |
| gh = Net::GitHub::Upload.new( |
| :login => login, |
| :token => token |
| ) |
| |
| version = ARGV[0] |
| |
| def upload(gh, version, repos, filename, description) |
| gh.upload(:repos => repos, |
| :file => "junit#{version}/#{filename}", |
| :description => description) |
| end |
| |
| upload(gh, version, repos, "junit-#{version}-src.jar", 'Source jar') |
| upload(gh, version, repos, "junit-#{version}.jar", 'Basic jar') |
| upload(gh, version, repos, "junit-dep-#{version}.jar", 'Jar without hamcrest') |
| upload(gh, version, repos, "junit#{version}.zip", 'Source zip') |
| |
| # # file upload |
| # direct_link = gh.upload( |
| # :repos => repos, |
| # :file => 'test/test', |
| # :description => "test file" |
| # ) |
| # # direct link is link to Amazon S3. |
| # # Because GitHub refrection for file changing is async, |
| # # if you get changed file synchronously, you use this "direct_link" |
| # |
| # # data upload |
| # # you can define content_type => Amazon S3 Content-Type |
| # time = Time.now.to_i |
| # direct_link = gh.upload( |
| # :repos => repos, |
| # :data => 'test', |
| # :name => "test_#{time}.txt", |
| # :content_type => 'text/plain', |
| # :description => "test file2" |
| # ) |
| # |
| # # replace file or data |
| # # thx id:rngtng ! |
| # direct_link = gh.replace( |
| # :repos => repos, |
| # :file => 'test/test', |
| # :description => "test file" |
| # ) |
| # direct_link = gh.replace( |
| # :repos => repos, |
| # :data => 'test', |
| # :name => "test_#{time}.txt", |
| # :content_type => 'text/plain', |
| # :description => "test file2" |
| # ) |