1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
# 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"
# )
|