New command 'stories_by_tag' in bin/gruta.
[gruta.git] / bin / gruta
blob1feb81f429bd18daf0a84e4489e2f2ae8a0dd6bc
1 #!/usr/bin/perl
3 use strict;
4 use warnings;
6 use File::Temp;
8 use Gruta;
9 use Gruta::Source::DBI;
10 use Gruta::Source::FS;
12 # = new_source($src_str);
13 # = Gruta->new( sources => $src );
15 my $X = {
16 'copy' => [
17 'copy {src} {dst}',
18 'Copies the full source {src} to {dst}',
19 sub {
20 my $g = init();
21 my $new_src = arg();
22 my $dst = new_source( $new_src );
24 $dst->create();
26 $g->transfer_to_source( $dst );
29 'topics' => [
30 'topics {src}',
31 'Lists the topics in {src}',
32 sub {
33 my $g = init();
35 foreach my $t ($g->topics()) {
36 print $t, "\n";
40 'topic' => [
41 'topic {src} {topic_id}',
42 'Dumps topic data',
43 sub {
44 my $g = init();
45 my $topic_id = arg();
47 my $topic = $g->topic($topic_id);
49 foreach my $f ($topic->afields()) {
50 print $f, ': ', ($topic->get($f) || ''), "\n";
54 'stories' => [
55 'stories {src} {topic_id}',
56 'Lists all stories of a topic',
57 sub {
58 my $g = init();
59 my $topic_id = arg();
61 foreach my $s ($g->stories($topic_id)) {
62 print $s, "\n";
66 'story' => [
67 'story {src} {topic_id} {id}',
68 'Dumps story data',
69 sub {
70 my $g = init();
71 my $topic_id = arg();
72 my $id = arg();
74 print get_story($g, $topic_id, $id);
77 'edit_story' => [
78 'edit_story {src} {topic_id} {id}',
79 'Calls $EDITOR to edit story data',
80 sub {
81 my $g = init();
82 my $topic_id = arg();
83 my $id = arg();
85 my $fh = File::Temp->new();
86 print $fh get_story($g, $topic_id, $id);
87 my $fn = $fh->filename();
88 $fh->close();
90 my $mtime = (stat($fn))[9];
91 system('$EDITOR ' . $fn);
93 if ($mtime != (stat($fn))[9]) {
94 save_story($g, $topic_id, $id, $fn);
98 'filter_story' => [
99 'filter_story {src} {topic_id} {id} {command}',
100 'Filters story data through command (STDIN, STDOUT)',
101 sub {
102 my $g = init();
103 my $topic_id = arg();
104 my $id = arg();
105 my $filter_cmd = arg();
107 my $fhr = File::Temp->new();
108 print $fhr get_story($g, $topic_id, $id);
109 my $fnr = $fhr->filename();
110 $fhr->close();
112 my $fhw = File::Temp->new();
113 my $fnw = $fhw->filename();
114 $fhw->close();
116 system("$filter_cmd < $fnr > $fnw");
118 save_story($g, $topic_id, $id, $fnw);
121 'create' => [
122 'create {src}',
123 'Creates {src}',
124 sub {
125 init();
128 'tags' => [
129 'tags {src}',
130 'Lists all tags in {src}',
131 sub {
132 my $g = init();
134 foreach my $t ($g->tags()) {
135 print join(' ', @{$t}), "\n";
139 'stories_by_date' => [
140 'stories_by_date {src} {topic(s)} {num} {offset}',
141 'Searches stories by date',
142 sub {
143 my $g = init();
144 my $topics = arg();
145 my $num = arg();
146 my $offset = arg();
148 if ($topics) {
149 $topics = [ split(':', $topics) ];
152 foreach my $s ($g->stories_by_date( $topics,
153 num => $num, offset => $offset) ) {
154 print join(' ', @{$s}), "\n";
158 'stats' => [
159 'stats {src}',
160 'Dumps statistics for {src}',
161 sub {
162 my $g = init();
163 my $n_topics = 0;
164 my $n_stories = 0;
165 my $n_hits = 0;
167 foreach my $t ($g->topics()) {
168 $n_topics++;
170 foreach my $s ($g->stories($t)) {
171 $n_stories++;
173 my $story = $g->story($t, $s);
175 $n_hits += $story->get('hits') || 0;
179 print "Topics: $n_topics, Stories: $n_stories, Hits: $n_hits\n";
182 'stories_by_tag' => [
183 'stories_by_tag {src} {tag(s)}',
184 'Searches stories by tag(s)',
185 sub {
186 my $g = init();
187 my $tags = arg();
189 foreach my $s ($g->search_stories_by_tag($tags)) {
190 print join(' ', @{$s}), "\n";
196 my $cmd = arg();
198 my $c;
200 if (not $c = $X->{$cmd}) {
201 $cmd = undef;
202 usage();
205 # execute
206 $c->[2]();
208 exit 0;
211 sub arg
213 if (@ARGV) {
214 return shift(@ARGV);
217 usage();
221 sub init
223 my $src = new_source(arg());
224 my $g = Gruta->new( sources => $src );
226 return $g;
230 sub usage
232 if ($cmd) {
233 my $c = $X->{$cmd};
235 print "Usage: gruta ", $c->[0], "\n\n\t", $c->[1], "\n";
237 else {
238 print "Usage: gruta {cmd} [args...]\n\n";
240 foreach my $c (values(%{$X})) {
241 print ' ', sprintf('%-50s %s',
242 $c->[0], $c->[1]), "\n";
246 exit 1;
249 sub new_source
251 my $src_str = shift;
252 my $src;
254 if ($src_str =~ /^dbi:/) {
255 $src = Gruta::Source::DBI->new( string => $src_str );
257 else {
258 $src = Gruta::Source::FS->new( path => $src_str );
261 return $src;
264 sub get_story
266 my $g = shift;
267 my $topic_id = shift;
268 my $id = shift;
269 my @r = ();
271 my $story = $g->story($topic_id, $id);
273 foreach my $f ($story->fields()) {
274 if ($f ne 'content') {
275 push (@r, $f . ': ' . ($story->get($f) || ''));
279 push(@r, 'tags: ' . join(', ', $story->tags()));
280 push(@r, '');
281 push(@r, $story->get('content'));
282 push(@r, '');
284 return join("\n", @r);
288 sub save_story
290 my $g = shift;
291 my $topic_id = shift;
292 my $id = shift;
293 my $fn = shift;
295 open F, $fn or die "Can't open $fn";
297 my $story = undef;
299 if ($id) {
300 $story = $g->story($topic_id, $id);
302 else {
303 $story = Gruta::Data::Story->new (
304 topic_id => $topic_id,
305 id => $id
309 while (<F>) {
310 chomp();
312 last if /^$/;
314 my ($key, $value) = (/^(\w+):\s*(.*)$/);
316 if ($key eq 'tags') {
317 $story->tags(split(/,\s*/, $value));
319 else {
320 $story->set($key, $value);
324 my $c = join('', <F>);
325 close F;
327 $story->set('content', $c);
329 if ($story->source()) {
330 $story->save();
332 else {
333 $g->insert_story($story);