source: subversion/applications/utils/revert/Revert.pm @ 16777

Last change on this file since 16777 was 16777, checked in by frederik, 10 years ago

add delete shortcut

File size: 4.6 KB
Line 
1#!/usr/bin/perl
2
3# Revert.pm
4# ---------
5#
6# Implements whole changeset reverts
7#
8# Part of the "osmtools" suite of programs
9# Originally written by Frederik Ramm <frederik@remote.org>; public domain
10
11package Revert;
12
13use strict;
14use warnings;
15
16use OsmApi;
17use Undo;
18
19# downloads a changeset and attempts to undo all changes
20# within that. currently transaction-based, so the revert will
21# fail if it cannot be done cleanly, but see variable $transaction.
22#
23# parameters:
24#   $undo_changeset: the changeset to nuke
25#   $changeset: the changeset in which the undo happens (must be open)
26# return:
27#   success=1 failure=undef
28
29sub revert
30{
31    my ($undo_changeset, $changeset) = @_;
32
33    my $resp = OsmApi::get("changeset/$undo_changeset/download");
34    if (!$resp->is_success)
35    {
36        print STDERR "changeset $undo_changeset cannot be retrieved: ".$resp->status_line."\n";
37        return undef;
38    }
39
40    my $objects = {};
41    my $action;
42
43    foreach (split(/\n/, $resp->content()))
44    { 
45        if (/<(modify|create|delete)/)
46        {
47            $action = $1;
48        }
49        elsif (/<(node|way|relation).*\sid=["'](\d+)["']/)
50        {
51            unshift(@{$objects->{"$action $1"}}, $2);
52        }
53    }
54
55    # first undelete nodes, ways, relations;
56    # then undo changes to nodes, ways, relations;
57    # then undo creations of relations, ways, nodes (note order).
58
59    my $success = [];
60    my $failure = [];
61    # set this to 0 if you want individual API requests rather than a changeset
62    # upload. this will be much slower but may be required if you cannot get all
63    # changes through due to problems.
64    my $transaction = 1;
65    # set this to 1 if you have a large number of object creations. this will
66    # bypass requesting object history for those, and simply try and delete them.
67    # which will fail if the object has been modified since.
68    my $delete_shortcut = 0;
69    my $oscpart;
70
71    foreach my $operation("delete node", "delete way", "delete relation",
72        "modify node", "modify way", "modify relation", 
73        "create relation", "create way", "create node")
74    {
75        foreach my $object(@{$objects->{$operation}})
76        {
77            my ($what, $objtype) = split(/ /, $operation);
78            if ($transaction)
79            {
80                # this collects all undos in one osc document.
81                if (($delete_shortcut) && ($what eq "create"))
82                {
83
84                    print STDERR "$objtype $object created; shortcut deletion\n";
85                    $oscpart->{"delete"} .= "<$objtype id=\"$object\" lat=\"0\" lon=\"0\" version=\"1\" changeset=\"$changeset\" />\n";
86                }
87                else
88                {
89                    my ($action, $xml) = Undo::determine_undo_action($objtype, $object, undef, $undo_changeset, $changeset);
90                    return undef unless (defined($action));
91                    $oscpart->{$action} .= $xml;
92                }
93            }
94            else
95            {
96                # this does individual undo operations. currently unused!
97                if (($delete_shortcut) && ($what eq "create"))
98                {
99                    print STDERR "$objtype $object created; shortcut deletion\n";
100                    my $resp = OsmApi::delete("$objtype/$object", "<osm version='0.6'><$objtype id=\"$object\" lat=\"0\" lon=\"0\" version=\"1\" changeset=\"$changeset\" /></osm>");
101                    if (!$resp->is_success)
102                    {
103                        push(@$failure, "$operation $object");
104                    }
105                    else
106                    {
107                        push(@$success, "$operation $object");
108                    }
109                }
110                else
111                {
112                    if (Undo::undo($objtype, $object, undef, $undo_changeset, $changeset))
113                    {
114                        push(@$success, "$operation $object");
115                    }
116                    else
117                    {
118                        push(@$failure, "$operation $object");
119                    }
120                }
121            }
122        }
123    }
124
125    if ($transaction)
126    {
127        my $osc = "<osmChange version='0.6' generator='osmtools'>\n";
128        foreach my $action("modify", "create", "delete")
129        {
130            if (defined($oscpart->{$action}))
131            {
132                $osc .= "<$action>\n".$oscpart->{$action}."</$action>\n";
133            }
134        }
135        $osc .= "</osmChange>\n";
136        my $res = OsmApi::post("changeset/$changeset/upload", $osc);
137        if (!($res->is_success))
138        {
139            print STDERR "changeset upload failed: ".$res->status_line."\n";
140            return undef;
141        }
142    }
143   
144    return 1;
145}
146
1471;
Note: See TracBrowser for help on using the repository browser.