source: subversion/applications/utils/revert/Undelete.pm @ 29411

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

undelete

File size: 4.3 KB
Line 
1#!/usr/bin/perl
2
3# Undelete.pm
4# -----------
5#
6# Implements undelete operations. This is very much like Undo.pm; the differences
7# are
8#
9# - undelete can only undo deletions, while undo can undo everything
10# - on the other hand, undelete undoes *any* deletion while undo requires you to specify
11#   which users's change you want to undo
12# - undelete can work recursively (the default)
13#
14# Part of the "osmtools" suite of programs
15# Originally written by Frederik Ramm <frederik@remote.org>; public domain
16
17package Undelete;
18
19use strict;
20use warnings;
21
22use OsmApi;
23
24our $globalListOfUndeletedStuff = {};
25
26# undeletes one object
27#
28# fails if the object is not deleted
29#
30# parameters:
31#   $what: 'node', 'way', or 'relation'
32#   $id: object id
33#   $changeset: id of changeset to use for undelete operation
34# return:
35#   success=1 failure=undef
36
37sub undelete
38{
39    my ($what, $id, $changeset) = @_;
40    my $recurse = 1;
41
42    my $xml = determine_undelete_action($what, $id, $changeset, $recurse, 0);
43    return undef unless defined ($xml);
44
45    my $resp = OsmApi::post("changeset/$changeset/upload", "<osmChange version='0.6'>\n<modify>\n$xml</modify></osmChange>");
46    if (!$resp->is_success)
47    {
48        print STDERR "$what $id cannot be undeleted: ".$resp->status_line."\n";
49        return undef;
50    }
51    return 1;
52}
53
54# the undelete workhorse; finds out which XML to upload to the API to
55# undelete an object.
56#
57# Parameters:
58# see sub undelete.
59#
60# Returns:
61# undef on error, else the new XML to send to the API.
62# The XML has to
63# be wrapped in <osm>...</osm> or inside a <modify>...</modify>
64# in a changeset upload.
65
66sub determine_undelete_action
67{
68    my ($what, $id, $changeset, $recursive, $indent) = @_;
69
70    my $copy=0;
71    my $out = "";
72    my $visible_version;
73    my $visible_user;
74    my $invisible_version;
75    my $invisible_user;
76    my $deleted;
77    my $members = [];
78
79    my $resp = OsmApi::get("$what/$id/history");
80    if (!$resp->is_success)
81    {
82        print STDERR " "x$indent;
83        print STDERR "$what $id cannot be retrieved: ".$resp->status_line."\n";
84        return undef;
85    }
86
87    foreach (split(/\n/, $resp->content()))
88    { 
89        if (/<$what/) 
90        { 
91            /\sid="([^"]+)"/ or die; 
92            die unless $id eq $1; 
93            /\sversion="([^"]+)"/ or die; 
94            my $version = $1;
95            /user="([^"]+)/;
96            my $user=$1;
97            /visible="([^"]+)/;
98            my $visible=$1;
99            if ($visible eq "true")
100            { 
101                $deleted = 0;
102                $copy = 1;
103                $visible_version = $version;
104                $visible_user = $user;
105                $out = $_;
106                $members = [];
107            } 
108            else 
109            {
110                $invisible_user = $user;
111                $invisible_version = $version;
112                $deleted = 1;
113                $copy = 0;
114            } 
115        } 
116        elsif ($copy) 
117        { 
118            $out.=$_; 
119            $copy=0 if (/<\/$what/);
120            if (/<nd ref=.(\d+)/)
121            {
122                push(@$members, { type => "node", id => $1 });
123            }
124            elsif (/<member.*type=.(way|node|relation).*id=.(\d+)/)
125            {
126                push(@$members, { type => $1, id => $2 });
127            }
128        } 
129    }; 
130
131    if ($deleted)
132    {
133        print STDERR " "x$indent;
134        print STDERR "$what $id deleted by user '$invisible_user'; restoring previous version $visible_version by '$visible_user'\n";
135        $out =~ s/version="$visible_version"/version="$invisible_version"/;
136        $out =~ s/changeset="\d+"/changeset="$changeset"/;
137        if ($recursive && scalar(@$members))
138        {
139            print STDERR " "x$indent;
140            print STDERR "recursively undeleting members of $what $id\n";
141            foreach (@$members)
142            {
143                if (!defined($globalListOfUndeletedStuff->{$_->{type}.$_->{id}}))
144                {
145                    my $ua = determine_undelete_action($_->{type}, $_->{id}, $changeset, 1, $indent + 2);
146                    $out = $ua . $out if defined($ua);
147                    $globalListOfUndeletedStuff->{$_->{type}.$_->{id}} = 1;
148                }
149            }
150        }
151        return $out;
152    }
153    else
154    {
155        print STDERR " "x$indent;
156        print STDERR "$what $id is not deleted\n";
157        return undef;
158    }
159}
160
1611;
Note: See TracBrowser for help on using the repository browser.