Skip to content

Commit ea15974

Browse files
author
damoxc
committed
update googlecode_upload to a later version that uploads correctly on windows.
bump version to 1.9.908 and re-tag builds as -dev
1 parent 4e92765 commit ea15974

3 files changed

Lines changed: 137 additions & 17 deletions

File tree

gc_upload.py

Lines changed: 135 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python
22
#
3-
# Copyright 2006 Google Inc. All Rights Reserved.
3+
# Copyright 2006, 2007 Google Inc. All Rights Reserved.
44
# Author: danderson@google.com (David Anderson)
55
#
66
# Script for uploading files to a Google Code project.
@@ -23,7 +23,10 @@
2323
# This is the password you use on googlecode.com for committing to
2424
# Subversion and uploading files. You can find your password by going
2525
# to http://code.google.com/hosting/settings when logged in with your
26-
# Gmail account.
26+
# Gmail account. If you have already committed to your project's
27+
# Subversion repository, the script will automatically retrieve your
28+
# credentials from there (unless disabled, see the output of '--help'
29+
# for details).
2730
#
2831
# If you are looking at this script as a reference for implementing
2932
# your own Google Code file uploader, then you should take a look at
@@ -38,7 +41,7 @@
3841
#
3942
# Questions, comments, feature requests and patches are most welcome.
4043
# Please direct all of these to the Google Code users group:
41-
# http://groups-beta.google.com/group/google-code-hosting
44+
# http://groups.google.com/group/google-code-hosting
4245

4346
"""Google Code file uploader script.
4447
"""
@@ -50,6 +53,55 @@
5053
import optparse
5154
import getpass
5255
import base64
56+
import sys
57+
58+
59+
def get_svn_config_dir():
60+
"""Return user's Subversion configuration directory."""
61+
try:
62+
from win32com.shell.shell import SHGetFolderPath
63+
import win32com.shell.shellcon
64+
except ImportError:
65+
# If we can't import the win32api, just use ~; this is right on unix, and
66+
# returns not entirely unreasonable results on Windows.
67+
return os.path.expanduser('~/.subversion')
68+
69+
# We're on Windows with win32api; use APPDATA.
70+
return os.path.join(SHGetFolderPath(0, win32com.shell.shellcon.CSIDL_APPDATA,
71+
0, 0).encode('utf-8'),
72+
'Subversion')
73+
74+
75+
def get_svn_auth(project_name, config_dir):
76+
"""Return (username, password) for project_name in config_dir."""
77+
78+
# Default to returning nothing.
79+
result = (None, None)
80+
81+
try:
82+
from svn.core import SVN_AUTH_CRED_SIMPLE, svn_config_read_auth_data
83+
from svn.core import SubversionException
84+
except ImportError:
85+
return result
86+
87+
realm = ('<https://%s.googlecode.com:443> Google Code Subversion Repository'
88+
% project_name)
89+
90+
# auth may be none even if no exception is raised, e.g. if config_dir does
91+
# not exist, or exists but has no entry for realm.
92+
try:
93+
auth = svn_config_read_auth_data(SVN_AUTH_CRED_SIMPLE, realm, config_dir)
94+
except SubversionException:
95+
auth = None
96+
97+
if auth is not None:
98+
try:
99+
result = (auth['username'], auth['password'])
100+
except KeyError:
101+
# Missing the keys, so return nothing.
102+
pass
103+
104+
return result
53105

54106

55107
def upload(file, project_name, user_name, password, summary, labels=None):
@@ -71,7 +123,11 @@ def upload(file, project_name, user_name, password, summary, labels=None):
71123
file_url: If the upload succeeded, the URL of the file on Google
72124
Code, None otherwise.
73125
"""
74-
if '@' in user_name: user_name = user_name.index[: user_name.index('@')]
126+
# The login is the user part of user@gmail.com. If the login provided
127+
# is in the full user@domain form, strip it down.
128+
if user_name.endswith('@gmail.com'):
129+
user_name = user_name[:user_name.index('@gmail.com')]
130+
75131
form_fields = [('summary', summary)]
76132
if labels is not None:
77133
form_fields.extend([('label', l.strip()) for l in labels])
@@ -124,7 +180,7 @@ def encode_upload_request(fields, file_path):
124180

125181
# Now add the file itself
126182
file_name = os.path.basename(file_path)
127-
f = open(file_path)
183+
f = open(file_path, 'rb')
128184
file_content = f.read()
129185
f.close()
130186

@@ -144,9 +200,74 @@ def encode_upload_request(fields, file_path):
144200
return 'multipart/form-data; boundary=%s' % BOUNDARY, CRLF.join(body)
145201

146202

203+
def upload_find_auth(file_path, project_name, summary, labels=None,
204+
config_dir=None, user_name=None, tries=3):
205+
"""Find credentials and upload a file to a Google Code project's file server.
206+
207+
file_path, project_name, summary, and labels are passed as-is to upload.
208+
209+
If config_dir is None, try get_svn_config_dir(); if it is 'none', skip
210+
trying the Subversion configuration entirely. If user_name is not None, use
211+
it for the first attempt; prompt for subsequent attempts.
212+
213+
Args:
214+
file_path: The local path to the file.
215+
project_name: The name of your project on Google Code.
216+
summary: A small description for the file.
217+
labels: an optional list of label strings with which to tag the file.
218+
config_dir: Path to Subversion configuration directory, 'none', or None.
219+
user_name: Your Google account name.
220+
tries: How many attempts to make.
221+
"""
222+
223+
if config_dir != 'none':
224+
# Try to load username/password from svn config for first try.
225+
if config_dir is None:
226+
config_dir = get_svn_config_dir()
227+
(svn_username, password) = get_svn_auth(project_name, config_dir)
228+
if user_name is None:
229+
# If username was not supplied by caller, use svn config.
230+
user_name = svn_username
231+
else:
232+
# Just initialize password for the first try.
233+
password = None
234+
235+
while tries > 0:
236+
if user_name is None:
237+
# Read username if not specified or loaded from svn config, or on
238+
# subsequent tries.
239+
sys.stdout.write('Please enter your googlecode.com username: ')
240+
sys.stdout.flush()
241+
user_name = sys.stdin.readline().rstrip()
242+
if password is None:
243+
# Read password if not loaded from svn config, or on subsequent tries.
244+
print 'Please enter your googlecode.com password.'
245+
print '** Note that this is NOT your Gmail account password! **'
246+
print 'It is the password you use to access Subversion repositories,'
247+
print 'and can be found here: http://code.google.com/hosting/settings'
248+
password = getpass.getpass()
249+
250+
status, reason, url = upload(file_path, project_name, user_name, password,
251+
summary, labels)
252+
# Returns 403 Forbidden instead of 401 Unauthorized for bad
253+
# credentials as of 2007-07-17.
254+
if status in [httplib.FORBIDDEN, httplib.UNAUTHORIZED]:
255+
# Rest for another try.
256+
user_name = password = None
257+
tries = tries - 1
258+
else:
259+
# We're done.
260+
break
261+
262+
return status, reason, url
263+
264+
147265
def main():
148266
parser = optparse.OptionParser(usage='googlecode-upload.py -s SUMMARY '
149-
'-p PROJECT -u USERNAME FILE')
267+
'-p PROJECT [options] FILE')
268+
parser.add_option('--config-dir', dest='config_dir', metavar='DIR',
269+
help='read svn auth data from DIR'
270+
' ("none" means not to use svn auth data)')
150271
parser.add_option('-s', '--summary', dest='summary',
151272
help='Short description of the file')
152273
parser.add_option('-p', '--project', dest='project',
@@ -162,31 +283,30 @@ def main():
162283
parser.error('File summary is missing.')
163284
elif not options.project:
164285
parser.error('Project name is missing.')
165-
elif not options.user:
166-
parser.error('User name is missing.')
167286
elif len(args) < 1:
168287
parser.error('File to upload not provided.')
288+
elif len(args) > 1:
289+
parser.error('Only one file may be specified.')
169290

170-
print 'Please enter your googlecode.com password.'
171-
print 'Note that this is NOT your main Gmail account password!'
172-
password = getpass.getpass()
173291
file_path = args[0]
174292

175293
if options.labels:
176294
labels = options.labels.split(',')
177295
else:
178296
labels = None
179297

180-
status, reason, url = upload(file_path, options.project,
181-
options.user, password,
182-
options.summary, labels)
298+
status, reason, url = upload_find_auth(file_path, options.project,
299+
options.summary, labels,
300+
options.config_dir, options.user)
183301
if url:
184302
print 'The file was uploaded successfully.'
185303
print 'URL: %s' % url
304+
return 0
186305
else:
187306
print 'An error occurred. Your file was not uploaded.'
188307
print 'Google Code upload server said: %s (%s)' % (reason, status)
308+
return 1
189309

190310

191311
if __name__ == '__main__':
192-
main()
312+
sys.exit(main())

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[egg_info]
2-
tag_build =
2+
tag_build = -dev

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ def upload(self, filename, comment):
244244

245245
setup(
246246
name = 'pymssql',
247-
version = '1.9.907',
247+
version = '1.9.908',
248248
description = 'A simple database interface to MS-SQL for Python.',
249249
long_description = 'A simple database interface to MS-SQL for Python.',
250250
author = 'Damien Churchill',

0 commit comments

Comments
 (0)