source: subversion/applications/utils/import/bulkupload/close.py @ 34714

Last change on this file since 34714 was 19989, checked in by balrog-kun, 10 years ago

Set the executable bits on the executables. (this directory still needs a clean-up)

  • Property svn:executable set to *
File size: 7.8 KB
Line 
1#! /usr/bin/python3
2# vim: fileencoding=utf-8 encoding=utf-8 et sw=4
3
4# Copyright (C) 2009 Jacek Konieczny <jajcus@jajcus.net>
5# Copyright (C) 2009 Andrzej Zaborowski <balrogg@gmail.com>
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20
21"""
22Closes a changeset, given id.
23"""
24
25__version__ = "$Revision: 21 $"
26
27import os
28import subprocess
29import sys
30import traceback
31import base64
32
33import http.client as httplib
34import xml.etree.cElementTree as ElementTree
35import urllib.parse as urlparse
36
37class HTTPError(Exception):
38    pass
39
40class OSM_API(object):
41    url = 'http://api.openstreetmap.org/'
42    def __init__(self, username = None, password = None):
43        if username and password:
44            self.username = username
45            self.password = password
46        else:
47            self.username = ""
48            self.password = ""
49        self.changeset = None
50        self.progress_msg = None
51
52    def __del__(self):
53        if self.changeset is not None:
54            self.close_changeset()
55
56    def msg(self, mesg):
57        sys.stderr.write("\r%s…                        " % (self.progress_msg))
58        sys.stderr.write("\r%s%s" % (self.progress_msg, mesg))
59        sys.stderr.flush()
60
61    def request(self, conn, method, url, body, headers, progress):
62        if progress:
63            self.msg("making request")
64            conn.putrequest(method, url)
65            self.msg("sending headers")
66            if body:
67                conn.putheader('Content-Length', str(len(body)))
68            for hdr, value in headers.iteritems():
69                conn.putheader(hdr, value)
70            self.msg("end of headers")
71            conn.endheaders()
72            self.msg(" 0%")
73            if body:
74                start = 0
75                size = len(body)
76                chunk = size / 100
77                if chunk < 16384:
78                    chunk = 16384
79                while start < size:
80                    end = min(size, start + chunk)
81                    conn.send(body[start:end])
82                    start = end
83                    self.msg("%2i%%" % (start * 100 / size))
84        else:
85            self.msg(" ")
86            conn.request(method, url, body, headers)
87
88    def _run_request(self, method, url, body = None, progress = 0, content_type = "text/xml"):
89        url = urlparse.urljoin(self.url, url)
90        purl = urlparse.urlparse(url)
91        if purl.scheme != "http":
92            raise ValueError("Unsupported url scheme: %r" % (purl.scheme,))
93        if ":" in purl.netloc:
94            host, port = purl.netloc.split(":", 1)
95            port = int(port)
96        else:
97            host = purl.netloc
98            port = None
99        url = purl.path
100        if purl.query:
101            url += "?" + query
102        headers = {}
103        if body:
104            headers["Content-Type"] = content_type
105
106        try_no_auth = 0
107
108        if not try_no_auth and not self.username:
109            raise HTTPError("Need a username")
110
111        try:
112            self.msg("connecting")
113            conn = httplib.HTTPConnection(host, port)
114#            conn.set_debuglevel(10)
115
116            if try_no_auth:
117                self.request(conn, method, url, body, headers, progress)
118                self.msg("waiting for status")
119                response = conn.getresponse()
120
121            if not try_no_auth or (response.status == httplib.UNAUTHORIZED and
122                    self.username):
123                if try_no_auth:
124                    conn.close()
125                    self.msg("re-connecting")
126                    conn = httplib.HTTPConnection(host, port)
127#                    conn.set_debuglevel(10)
128
129                creds = self.username + ":" + self.password
130                headers["Authorization"] = "Basic " + \
131                        base64.b64encode(bytes(creds, "utf8")).decode("utf8")
132                        # ^ Seems to be broken in python3 (even the raw
133                        # documentation examples don't run for base64)
134                self.request(conn, method, url, body, headers, progress)
135                self.msg("waiting for status")
136                response = conn.getresponse()
137
138            if response.status == httplib.OK:
139                self.msg("reading response")
140                sys.stderr.flush()
141                response_body = response.read()
142            else:
143                raise HTTPError("%02i: %s (%s)" % (response.status,
144                        response.reason, response.read()))
145        finally:
146            conn.close()
147        return response_body
148
149    def create_changeset(self, created_by, comment):
150        if self.changeset is not None:
151            raise RuntimeError("Changeset already opened")
152        self.progress_msg = "I'm creating the changeset"
153        self.msg("")
154        sys.stderr.flush()
155        root = ElementTree.Element("osm")
156        tree = ElementTree.ElementTree(root)
157        element = ElementTree.SubElement(root, "changeset")
158        ElementTree.SubElement(element, "tag", {"k": "created_by", "v": created_by})
159        ElementTree.SubElement(element, "tag", {"k": "comment", "v": comment})
160        body = ElementTree.tostring(root, "utf-8")
161        reply = self._run_request("PUT", "/api/0.6/changeset/create", body)
162        changeset = int(reply.strip())
163        self.msg("done. Id: %i" % (changeset,))
164        sys.stderr("\n")
165        self.changeset = changeset
166
167    def upload(self, change):
168        if self.changeset is None:
169            raise RuntimeError("Changeset not opened")
170        self.progress_msg = "Now I'm sending changes"
171        self.msg("")
172        sys.stderr.flush()
173        for operation in change:
174            if operation.tag not in ("create", "modify", "delete"):
175                continue
176            for element in operation:
177                element.attrib["changeset"] = str(self.changeset)
178        body = ElementTree.tostring(change, "utf-8")
179        reply = self._run_request("POST", "/api/0.6/changeset/%i/upload"
180                                                % (self.changeset,), body, 1)
181        self.msg("done.")
182        sys.stderr.write("\n")
183        return reply
184
185    def close_changeset(self):
186        if self.changeset is None:
187            raise RuntimeError("Changeset not opened")
188        self.progress_msg = "Closing"
189        self.msg("")
190        sys.stderr.flush()
191        sys.stderr.flush()
192        reply = self._run_request("PUT", "/api/0.6/changeset/%i/close"
193                                                    % (self.changeset,))
194        self.changeset = None
195        self.msg("done, too.")
196        sys.stderr.write("\n")
197
198try:
199    this_dir = os.path.dirname(__file__)
200    try:
201        version = int(subprocess.Popen(["svnversion", this_dir], stdout = subprocess.PIPE).communicate()[0].strip())
202    except:
203        version = 1
204    if len(sys.argv) != 2:
205        sys.stderr.write("Synopsis:\n")
206        sys.stderr.write("    %s <changeset-id>\n", sys.argv[0])
207        sys.exit(1)
208
209    login = input("OSM login: ")
210    if not login:
211        sys.exit(1)
212    password = input("OSM password: ")
213    if not login:
214        sys.exit(1)
215
216    api = OSM_API(login, password)
217    api.changeset = int(sys.argv[1])
218    api.close_changeset()
219except HTTPError as err:
220    sys.stderr.write(str(err) + "\n")
221    sys.exit(1)
222except Exception as err:
223    sys.stderr.write(str(err) + "\n")
224    traceback.print_exc(file=sys.stderr)
225    sys.exit(1)
Note: See TracBrowser for help on using the repository browser.