8 use Data::Dump qw/dump/;
9 use File::Path qw/mkpath/;
12 use HTTP::Request::Common;
16 use lib qw(lib ../lib);
17 use Media::Type::Simple;
22 # 04/26/09 21:12:28 CEST Dobrica Pavlinusic <dpavlin@rot13.org>
24 our $couchdb = $ENV{COUCHDB} || 'http://localhost:5984/';
26 our ( $command, $database, $design ) = @ARGV;
28 die "usage: $0 [push|pull] database [design]\n" unless $database;
31 my $ua = LWP::UserAgent->new;
35 if ( $path =~ m{/} ) {
38 mkpath $dir if ! -e $dir;
45 return if $path =~ m{(_.*|.*\.(push|pull)\.js)$};
46 system "svn add --parents $path";
50 my ( $path, $content ) = @_;
53 File::Slurp::write_file $path, $content;
54 print "$path ", -s $path, " bytes created\n";
58 sub write_attachment {
60 my $file = "_attachemnts/$path";
62 $ua->mirror( "$couchdb/$database/_design/$design/$path", $file );
63 print "detached $file ", -s $file, " bytes\n";
69 my ( $tree, $path ) = @_;
72 if ( $ref eq 'HASH' ) {
73 foreach my $child ( keys %$tree ) {
74 if ( $child eq '_attachments' ) {
75 write_attachment $_ foreach keys %{ $tree->{$child} };
77 unroll( $tree->{$child}, $path ? "$path/$child" : $child );
81 warn "UNSUPPORTED $path $ref ", dump( $tree );
82 write_file "$path.json", to_json $tree;
83 } elsif ( $ref eq '' ) {
85 if ( $tree =~ m[^\s*(function(.*){.*}|/\*|//|var)]is ) {
87 } elsif ( $tree =~ m{<%=.*%>} ) { # couchapp template
90 warn "# can't detect type of $path\n";
93 write_file $path, $tree;
101 my $url = "$couchdb/$database/_design/$design";
104 my $response = $ua->get( $url );
105 die $response->status_line if $response->is_error;
107 my $json = $response->decoded_content;
108 write_file "../$database-$design.pull.js", $json;
110 unroll( from_json $json, '' );
117 $ua->request( HTTP::Request::Common::PUT( "http://localhost:5984/$database" ) ) && warn "# created database $database\n";
121 find({ no_chdir => 1, wanted => sub {
122 my $path = $File::Find::name;
123 return unless -f $path;
124 return if $path =~ m{/\.svn};
130 if ( $path =~ m{_attachemnts/(.+)} ) {
133 my $content_type = 'text/plain';
134 $content_type = type_from_ext($1) if $filename =~ m{\.(\w+)$};
136 my $data = File::Slurp::read_file( $path );
137 $data = encode_base64( $data );
138 # XXX inline attachments must be single line
139 # XXX http://wiki.apache.org/couchdb/HTTP_Document_API
140 $data =~ s/[\n\r]+//gs;
141 $json->{_attachments}->{ $filename } = {
142 content_type => $content_type,
148 my $data = File::Slurp::read_file( $path );
149 $path =~ s[/]['}->{']g;
150 $path =~ s{\.\w+$}{};
151 my $code = "\$json->{'$path'} = \$data;";
153 die "ERROR in $code: $@" if $@;
154 # warn "## json = ",dump( $json );
157 if ( ! defined $json->{_id} ) {
158 warn "creating _id for document\n";
159 $json->{_id} = $$ . '-' . time();
161 delete( $json->{_rev} ) && warn "removing _rev from document\n";
163 print "push $database/_design/$design\n";
164 write_file "../$database-$design.push.js", to_json $json;
166 my $url = "$couchdb/$database/_design/$design";
168 my $response = $ua->request(
169 HTTP::Request::Common::PUT(
171 'Content-Type' => 'application/json',
172 Content => to_json $json,
176 if ( $response->code == 409 ) {
177 warn "## update $url\n";
178 my $response = $ua->get( $url );
179 die $response->status_line if $response->is_error;
181 my $data = from_json $response->decoded_content;
182 $json->{$_} = $data->{$_} foreach ( '_rev', '_id' );
184 $response = $ua->request( HTTP::Request::Common::PUT($url, 'Content-Type' => 'application/json', Content => to_json $json ) );
185 die $response->status_line if $response->is_error;
186 warn "push updated $url\n";
188 die $response->status_line if $response->is_error;
189 warn "push new $url\n";
197 if ( $command eq 'push' ) {
199 my @designs = map { s{/.+$}{}; $_ } glob '*/views';
200 @designs = ( $design ) if $design;
202 foreach my $design ( @designs ) {
205 push_design( $design );
210 } elsif ( $command eq 'pull' ) {
212 my $designs = from_json $ua->get( "$couchdb/$database/_all_docs?startkey=%22_design%2F%22&endkey=%22_design0%22" )->decoded_content;
216 $name =~ s{^_design/}{};
218 } @{ $designs->{rows} }
221 warn "# $database/_design ",dump( @designs );
223 @designs = ( $design ) if $design;
225 foreach my $design ( @designs ) {
227 mkdir $design unless -e $design;
229 pull_design( $design );
235 die "$0: unknown command $command";