Piggy 0.4.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/CHANGES.txt +91 -0
  2. data/INSTALL.txt +77 -0
  3. data/LICENCE.txt +339 -0
  4. data/README.txt +27 -0
  5. data/UNINSTALL.txt +24 -0
  6. data/bin/directory_diff +6 -0
  7. data/bin/ftp_browser +6 -0
  8. data/bin/piggy +6 -0
  9. data/lib/directory_diff.rb +35 -0
  10. data/lib/ftp_browser.rb +33 -0
  11. data/lib/icons/auto-select-for-del.ico +0 -0
  12. data/lib/icons/auto-select-right.ico +0 -0
  13. data/lib/icons/auto-upload-right.ico +0 -0
  14. data/lib/icons/back.ico +0 -0
  15. data/lib/icons/checked.ico +0 -0
  16. data/lib/icons/copy.png +0 -0
  17. data/lib/icons/cut.png +0 -0
  18. data/lib/icons/dir.ico +0 -0
  19. data/lib/icons/dirup.ico +0 -0
  20. data/lib/icons/file.ico +0 -0
  21. data/lib/icons/fileopen.png +0 -0
  22. data/lib/icons/filesave.ico +0 -0
  23. data/lib/icons/gallery.ico +0 -0
  24. data/lib/icons/generate.ico +0 -0
  25. data/lib/icons/minus.png +0 -0
  26. data/lib/icons/move-right-dir.ico +0 -0
  27. data/lib/icons/move-right-file.ico +0 -0
  28. data/lib/icons/newer-file.ico +0 -0
  29. data/lib/icons/next-image.ico +0 -0
  30. data/lib/icons/paste.png +0 -0
  31. data/lib/icons/plus.png +0 -0
  32. data/lib/icons/preview.png +0 -0
  33. data/lib/icons/previous-image.ico +0 -0
  34. data/lib/icons/reload.ico +0 -0
  35. data/lib/icons/remove-selected.ico +0 -0
  36. data/lib/icons/rotate.ico +0 -0
  37. data/lib/icons/slides.ico +0 -0
  38. data/lib/icons/stop-slides.ico +0 -0
  39. data/lib/icons/unchecked-dir.ico +0 -0
  40. data/lib/icons/unchecked.ico +0 -0
  41. data/lib/icons/upload-selected.ico +0 -0
  42. data/lib/icons/upload.ico +0 -0
  43. data/lib/piggy-core/alive_check.rb +44 -0
  44. data/lib/piggy-core/debug.rb +21 -0
  45. data/lib/piggy-core/encoding.rb +11 -0
  46. data/lib/piggy-core/environment.rb +66 -0
  47. data/lib/piggy-core/exifr_adapter.rb +85 -0
  48. data/lib/piggy-core/file_info.rb +218 -0
  49. data/lib/piggy-core/ftp_adapter.rb +106 -0
  50. data/lib/piggy-core/htmlgen.rb +242 -0
  51. data/lib/piggy-core/nconvert_thumbsgen.rb +73 -0
  52. data/lib/piggy-core/options.rb +116 -0
  53. data/lib/piggy-core/options_persistence.rb +54 -0
  54. data/lib/piggy-core/progress.rb +48 -0
  55. data/lib/piggy-core/rmagick_thumbnail_page_generator.rb +30 -0
  56. data/lib/piggy-core/thumbnail_generator.rb +79 -0
  57. data/lib/piggy-core/thumbnail_page_generator.rb +542 -0
  58. data/lib/piggy-core/upload_info.rb +41 -0
  59. data/lib/piggy-core/version.rb +18 -0
  60. data/lib/piggy-core/winshell.rb +240 -0
  61. data/lib/piggy-gui/directory_diff_widget.rb +398 -0
  62. data/lib/piggy-gui/filtered_file_list.rb +243 -0
  63. data/lib/piggy-gui/fox_thumbsgen.rb +18 -0
  64. data/lib/piggy-gui/ftp_browser_widget.rb +395 -0
  65. data/lib/piggy-gui/html_generation_dialog.rb +157 -0
  66. data/lib/piggy-gui/image_processor.rb +140 -0
  67. data/lib/piggy-gui/multiimagecanvas.rb +163 -0
  68. data/lib/piggy-gui/options_dialog.rb +85 -0
  69. data/lib/piggy-gui/piggy_image_browser.rb +776 -0
  70. data/lib/piggy-gui/pipe_log.rb +67 -0
  71. data/lib/piggy-gui/progress_with_dialog.rb +51 -0
  72. data/lib/piggy-gui/require-fox.rb +87 -0
  73. data/lib/piggy.rb +35 -0
  74. data/lib/templates/fuss.htm +10 -0
  75. data/lib/templates/kopf.htm +13 -0
  76. data/lib/templates/navigation.htm +11 -0
  77. data/lib/templates/slideshow.htm +129 -0
  78. data/lib/templates/slideshow.js +691 -0
  79. data/lib/templates/styles/basic/style.css +27 -0
  80. data/lib/templates/styles/black/style.css +64 -0
  81. data/lib/templates/styles/roundedbox/roundedbox_lo.gif +0 -0
  82. data/lib/templates/styles/roundedbox/roundedbox_lu.gif +0 -0
  83. data/lib/templates/styles/roundedbox/roundedbox_ro.gif +0 -0
  84. data/lib/templates/styles/roundedbox/roundedbox_ru.gif +0 -0
  85. data/lib/templates/styles/roundedbox/style.css +70 -0
  86. data/lib/templates/styles/shadow/lo.gif +0 -0
  87. data/lib/templates/styles/shadow/lu.gif +0 -0
  88. data/lib/templates/styles/shadow/ro.gif +0 -0
  89. data/lib/templates/styles/shadow/ru.gif +0 -0
  90. data/lib/templates/styles/shadow/style.css +63 -0
  91. data/test/file_info_test.rb +117 -0
  92. data/test.rb +8 -0
  93. data/web/IMAGE_PROCESSING.txt +53 -0
  94. data/web/INSTALL.txt +74 -0
  95. data/web/extern.gif +0 -0
  96. data/web/ftp-browser.png +0 -0
  97. data/web/index-de.html +60 -0
  98. data/web/index.html +57 -0
  99. data/web/piggy.png +0 -0
  100. data/web/style.css +14 -0
  101. metadata +177 -0
@@ -0,0 +1,542 @@
1
+ #!/usr/bin/ruby
2
+ # $Id: thumbnail_page_generator.rb 195 2008-05-29 21:32:40Z Sascha $
3
+
4
+ require 'ftools'
5
+ require 'piggy-core/environment'
6
+ require 'piggy-core/htmlgen'
7
+ require 'piggy-core/options'
8
+
9
+ # ThumbnailPageGenerator generates html-pages for an internet picture
10
+ # album. It does no image processing at all, this has to happen outside.
11
+ #
12
+ # Generation without frames:
13
+ #
14
+ # outputPath
15
+ # |
16
+ # +----subDir
17
+ # |
18
+ # +----style
19
+ # | |
20
+ # | ...(stylesheet and background images)
21
+ # |
22
+ # +----index.htm
23
+ # |
24
+ # ...(3 files per image)
25
+ #
26
+ # The 3 files per image are:
27
+ # - thumbnail image
28
+ # - image
29
+ # - image embedded in html with some basic navigation
30
+ #
31
+ # Generation with frames:
32
+ #
33
+ # outputPath
34
+ # |
35
+ # +----subDir
36
+ # | |
37
+ # | +----index.htm
38
+ # | |
39
+ # | ...(3 files per image)
40
+ # |
41
+ # +----style
42
+ # | |
43
+ # | ...(stylesheet and background images)
44
+ # |
45
+ # +----index.htm
46
+ # |
47
+ # +----"#{subDir}.htm"
48
+ # |
49
+ # +----navigation.htm (updated)
50
+ # |
51
+ # +----kopf.htm
52
+ # |
53
+ # +----fuss.htm
54
+ #
55
+ # You may replace kopf.htm and fuss.htm by your own files.
56
+ class ThumbnailPageGenerator < HtmlGenerator
57
+
58
+ attr_reader(:client, :imageOutputPath, :indexName, :subDir)
59
+ attr_writer(:client)
60
+
61
+ HtmlExt = '.htm'
62
+ DownloadName = "download.zip"
63
+ SlideshowName = "slideshow"
64
+
65
+ def initialize(options)
66
+ @client = self
67
+ @options = options
68
+ @indexName = 'index' + HtmlExt
69
+ end
70
+
71
+ def setOutputDirectory(outputDir)
72
+ @subDir = outputDir
73
+ @imageOutputPath = File.join(outputPath, outputDir)
74
+ end
75
+
76
+ # Overwrite this, if you convert arbitrary image types into
77
+ # output formats suitable for web pages, e. g. jpg or png
78
+ def conversionTypeFor(type)
79
+ type
80
+ end
81
+
82
+ def imageName(info)
83
+ escapeHtml("#{info.nameWithoutExtension}.#{conversionTypeFor(info.extension)}")
84
+ end
85
+
86
+ ##
87
+ # Set path to directory containing the original image files
88
+ def setInputDirectory(inputDir)
89
+ @inputDir = inputDir
90
+ end
91
+
92
+ def setFiles(fileInfos)
93
+ @inputFilenames = fileInfos
94
+ end
95
+
96
+ def setTitle(title)
97
+ @title = title
98
+ end
99
+
100
+ def sep
101
+ return "#{File::SEPARATOR}"
102
+ end
103
+
104
+ def back
105
+ return "..#{sep}"
106
+ end
107
+
108
+ def outputPath
109
+ return @options.localDestinationPath
110
+ end
111
+
112
+ def mainIndexPath
113
+ return @options.generateFramePage ? outputPath : imageOutputPath
114
+ end
115
+
116
+ def mainIndexWithPath
117
+ return mainIndexPath + sep + indexName
118
+ end
119
+
120
+ def getBacklinkString
121
+ @options.generateFramePage? ? back + subDir + HtmlExt : indexName
122
+ end
123
+
124
+ def subStylesheetUrl
125
+ if @options.generateFramePage?
126
+ back + mainStylesheetUrl
127
+ else
128
+ mainStylesheetUrl
129
+ end
130
+ end
131
+
132
+ def mainStylesheetUrl
133
+ 'style/style.css'
134
+ end
135
+
136
+ # Add important meta tags
137
+ def commonHead
138
+ norobots()
139
+ # the next tag will tell Piggy that this file may be
140
+ # overwritten by Piggy
141
+ meta({
142
+ "name" => "generator",
143
+ "content" =>"Piggy"})
144
+ utf8()
145
+ end
146
+
147
+ # Check if this file has been written by Piggy
148
+ def isPiggyFile?(file)
149
+ ret = false
150
+ File.open(file, 'r') { |fp|
151
+ while !ret && fp.gets
152
+ ret = true if(/<meta.*name="generator"/ && /<meta.*content="Piggy"/)
153
+ end
154
+ }
155
+ return ret
156
+ end
157
+
158
+ def buildHtmlPagesForImages(progress)
159
+ progress.setTask("Generate html", @inputFilenames.size)
160
+ maxInd = @inputFilenames.size - 1
161
+ backlink = getBacklinkString
162
+ (0..maxInd).each { | i |
163
+ currentInfo = @inputFilenames[i]
164
+ predInfo = @inputFilenames[i == 0 ? maxInd : i - 1]
165
+ succInfo = @inputFilenames[i == maxInd ? 0 : i + 1]
166
+ current = currentInfo.nameWithoutExtension
167
+ comment = currentInfo.comment
168
+ pred = predInfo.nameWithoutExtension
169
+ succ = succInfo.nameWithoutExtension
170
+ progress.setProgress(current, 1)
171
+ newTransitional
172
+ html {
173
+ head {
174
+ title() { escapeHTML(current) }
175
+ commonHead
176
+ stylesheet subStylesheetUrl
177
+ }
178
+ body({"class"=>"image_page"}) {
179
+ a({"HREF" => escapeHTML(pred) + HtmlExt}){
180
+ addHtml(escapeHTML(i == 0 ? 'letztes' : 'voriges'))
181
+ }
182
+ a({"HREF" => escapeHTML(backlink) }) {
183
+ addHtml(escapeHTML('�bersicht'))
184
+ }
185
+ a({"HREF" => escapeHTML(succ) + HtmlExt}) {
186
+ addHtml(escapeHTML(i == maxInd ? 'erstes' : 'n�chstes'))
187
+ }
188
+ br
189
+ img(imageName(currentInfo), escapeHTML(current))
190
+ br
191
+ addHtml(escapeHTML(comment))
192
+ }
193
+ }
194
+ File.open(File.join(imageOutputPath, current + HtmlExt), 'w') { | fp |
195
+ fp.print(getPage)
196
+ }
197
+ }
198
+ end
199
+
200
+ def buildSlideshowList(pathToImages = nil)
201
+ File.open(File.join(imageOutputPath, 'images.js'), 'w') { | fp |
202
+ fp.print("var images = new Array(\n")
203
+ maxInd = @inputFilenames.size - 1
204
+ (0..maxInd).each { | i |
205
+ current = slideshowImage(@inputFilenames[i], pathToImages)
206
+ fp.print("'#{current}'")
207
+ fp.print(i == maxInd ? "\n" : ",\n")
208
+ }
209
+ fp.print(")\n")
210
+ }
211
+ unless @inputFilenames.empty?
212
+ updateSlideshowTemplate(slideshowImage(@inputFilenames[1], pathToImages))
213
+ end
214
+ end
215
+
216
+ def slideshowImage(fileName, pathToImages = nil)
217
+ img = imageName(fileName)
218
+ if pathToImages
219
+ img = 'file:///' + File.join(WinShell.instance.rubyPath(pathToImages), img)
220
+ end
221
+ return img
222
+ end
223
+
224
+ def updateSlideshowTemplate(imageFile)
225
+ reset
226
+ file = File.join(imageOutputPath, 'slideshow.htm')
227
+ lines = File.readlines(file)
228
+ backlink = "href=\"#{getBacklinkString}\""
229
+ File.open(file, 'w') { |fp|
230
+ lines.each { |line|
231
+ line = line.gsub('PLACEHOLDER_FOR_IMAGE_NAME', imageFile)
232
+ line = line.gsub('href="index.htm"', backlink)
233
+ fp.print(line)
234
+ }
235
+ }
236
+ end
237
+
238
+ def bytesAsString(bytes)
239
+ kb = bytes/1024
240
+ return "#{kb} KB" if kb < 1024
241
+ mb = kb/1024
242
+ return "#{mb} MB" if mb < 1024
243
+ gb = mb/1024
244
+ return "#{gb} GB"
245
+ end
246
+
247
+ def buildThumbnailPage(sizeOfZipfile = -1)
248
+ numCol = 5
249
+ matrix = Array.new(@inputFilenames.size() / numCol)
250
+ row = -1
251
+ col = 0
252
+ @inputFilenames.each { |info|
253
+ if col % numCol == 0
254
+ col = 0
255
+ row += 1
256
+ matrix[row] = Array.new(numCol)
257
+ end
258
+ matrix[row][col] = info
259
+ col += 1
260
+ }
261
+ newTransitional
262
+ html() {
263
+ head() {
264
+ title() { @title }
265
+ commonHead()
266
+ stylesheet subStylesheetUrl
267
+ }
268
+ body({'class'=>'thumbs'}){
269
+ h3({}){ addHtml(escapeHTML(@title)) }
270
+ if(sizeOfZipfile > 0)
271
+ a({"href" => DownloadName }) { addHtml(DownloadName) }
272
+ addHtml("(#{bytesAsString(sizeOfZipfile)})")
273
+ end
274
+ if(@options.addSlideshow?)
275
+ a({"href" => File.join('slideshow.htm'), "target" => "_top"}) {
276
+ addHtml(SlideshowName)
277
+ }
278
+ end
279
+ imageTable({'class'=>'table'}) {
280
+ matrix.each { |row|
281
+ imageRow {
282
+ row.each { |info|
283
+ if info
284
+ imageColumn {
285
+ addPreview(info)
286
+ }
287
+ end
288
+ }
289
+ }
290
+ }
291
+ }
292
+ }
293
+ }
294
+ File.open(File.join(imageOutputPath, indexName), 'w') { | fp |
295
+ fp.print(getPage) }
296
+ end
297
+
298
+ def imageTable(params, &block)
299
+ if @options.useTable?
300
+ table(params, &block)
301
+ else
302
+ dl(params, &block)
303
+ end
304
+ end
305
+
306
+ def imageRow(&block)
307
+ if @options.useTable?
308
+ tr({}, &block)
309
+ else
310
+ block.call
311
+ end
312
+ end
313
+
314
+ def imageColumn(&block)
315
+ if @options.useTable?
316
+ td({}, &block)
317
+ else
318
+ dd({}, &block)
319
+ end
320
+ end
321
+
322
+ def addPreview(info)
323
+ div({'class' => 'preview'}){
324
+ div({'class' => 'thumb'}){
325
+ p {
326
+ name = escapeHtml(info.nameWithoutExtension)
327
+ a({
328
+ "href" => name + HtmlExt,
329
+ 'target' => '_top'}
330
+ ) {
331
+ img('t_'+ imageName(info), name)
332
+ }
333
+ }
334
+ }
335
+ }
336
+ end
337
+
338
+ def frameText()
339
+ newFrame
340
+ html(){
341
+ head(){
342
+ title { 'Bildindex' }
343
+ commonHead
344
+ stylesheet mainStylesheetUrl
345
+ }
346
+ frameset({'rows'=>'14%,65%,21%'}){
347
+ frame({
348
+ 'src'=>"kopf.htm",
349
+ 'name'=>"Kopf",
350
+ 'scrolling'=>"no",
351
+ 'frameborder'=>"0"
352
+ })
353
+ frameset({'cols'=>"15%,85%"}){
354
+ frame({
355
+ 'src'=>"navigation.htm",
356
+ 'name'=>"Navigation",
357
+ 'scrolling'=>"yes",
358
+ 'frameborder'=>"0"
359
+ })
360
+ frame({
361
+ 'src'=>"#{subDir + sep + indexName}",
362
+ 'name'=>"Daten",
363
+ 'frameborder'=>"0"
364
+ })
365
+ }
366
+ frame({
367
+ 'src'=>"fuss.htm",
368
+ 'name'=>"Fuss",
369
+ 'scrolling'=>"no",
370
+ 'frameborder'=>"0"
371
+ })
372
+ noframes(){
373
+ cr
374
+ addHtml('Ohne Frames siehe: ')
375
+ a({'href'=>"navigation.htm"}){
376
+ addHtml('Navigationsleiste')
377
+ }
378
+ }
379
+ }
380
+ }
381
+ return getPage
382
+ end
383
+
384
+ def buildFramePage()
385
+ content = frameText
386
+ writeFile(File.join(outputPath, subDir + HtmlExt), content)
387
+ writeFile(File.join(outputPath, indexName), content)
388
+ end
389
+
390
+ def writeFile(file, content)
391
+ return if File.exists?(file) && !isPiggyFile?(file)
392
+ File.open(file, 'w') { |fp| fp.print(content) }
393
+ end
394
+
395
+ def buildZipfile(nameOfZipFile, progress)
396
+ require 'zip/zip'
397
+ progress.setTask("Creating zipfile", @inputFilenames.size)
398
+ Zip::ZipFile.open(nameOfZipFile, Zip::ZipFile::CREATE) {
399
+ |zipfile|
400
+ zipfile.mkdir(subDir)
401
+ @inputFilenames.each do
402
+ |info|
403
+ progress.setProgress("Zip #{info.name}", 1)
404
+ entry = File.join(subDir, info.name)
405
+ src = info.nameWithPath
406
+ zipfile.add(entry, src)
407
+ end
408
+ }
409
+ end
410
+
411
+ def copyTemplateFiles()
412
+ if @options.generateFramePage
413
+ copyTemplates(['navigation.htm', 'kopf.htm', 'fuss.htm'],
414
+ outputPath)
415
+ copyStyle(outputPath)
416
+ else
417
+ copyStyle(imageOutputPath)
418
+ end
419
+ if @options.addSlideshow?
420
+ copyTemplates(['slideshow.htm', 'slideshow.js'], imageOutputPath)
421
+ link = "<link href=\"#{subStylesheetUrl}\" rel=\"stylesheet\" type=\"text/css\">"
422
+ insertInFile(File.join(imageOutputPath, 'slideshow.htm'),
423
+ /<!--STYLE-->/, link)
424
+ end
425
+ end
426
+
427
+ def styleSourceDir
428
+ File.join(PIGGY_PATH, 'templates/styles', @options.style)
429
+ end
430
+
431
+ def copyStyle(targetPath)
432
+ targetDir = File.join(targetPath, 'style')
433
+ File.makedirs(targetDir)
434
+ Dir[File.join(styleSourceDir, '*.*')].each { |fName|
435
+ File.copy(fName, targetDir) unless File.exists?(File.join(targetDir, fName))
436
+ }
437
+ end
438
+
439
+ def copyTemplates(files, targetPath)
440
+ files.each do
441
+ |fName|
442
+ unless File.exists?(File.join(targetPath, fName))
443
+ templateFile = File.join(PIGGY_PATH, 'templates', fName)
444
+ File.copy(templateFile, targetPath)
445
+ end
446
+ end
447
+ end
448
+
449
+ # Insert insertion into file after any match of pattern
450
+ def insertInFile(file, pattern, insertion)
451
+ lines = File.readlines(file)
452
+ File.open(file, 'w') { |fp|
453
+ lines.each { |line|
454
+ fp.print(line)
455
+ fp.print(insertion) if line =~ pattern
456
+ }
457
+ }
458
+ end
459
+
460
+ def updateNavigationFrame()
461
+ reset
462
+ navFile = File.join(outputPath, 'navigation.htm')
463
+ a({
464
+ 'href' => escapeHtml(subDir) + '/index.htm',
465
+ 'target' => 'Daten'}) {
466
+ addHtml(escapeHTML(@title))
467
+ }
468
+ br
469
+ addHtml("\n")
470
+ link = getPage
471
+ insertInFile(navFile, /<!--NAV-->/, link)
472
+ end
473
+
474
+ def error msg
475
+ puts "Error: #{msg}"
476
+ return false
477
+ end
478
+
479
+ ##
480
+ # Will create the directory for all the '3 files per image'
481
+ # unless directory exits
482
+ def createSubdir
483
+ subDirWithPath = File.join(outputPath, subDir)
484
+ Dir.mkdir(subDirWithPath) unless File.directory?(subDirWithPath)
485
+ end
486
+
487
+ ##
488
+ # Central bublic doit function
489
+ def generate(progress, overwrite=false, addZipfile=false)
490
+ if File.directory?(File.join(outputPath, subDir)) && !overwrite
491
+ return error("#{subDir} allready exists")
492
+ end
493
+ unless File.directory?(outputPath)
494
+ return error("#{outputPath} ist no directory}")
495
+ end
496
+ progress.setTask("Creating directory")
497
+ createSubdir
498
+ sizeOfZipfile = -1
499
+ if addZipfile
500
+ nameOfZipFile = File.join(outputPath, subDir, DownloadName)
501
+ buildZipfile(nameOfZipFile, progress)
502
+ sizeOfZipfile = File.size(nameOfZipFile) if File.exists?(nameOfZipFile)
503
+ end
504
+ buildHtmlPagesForImages(progress)
505
+ buildThumbnailPage(sizeOfZipfile)
506
+ copyTemplateFiles
507
+ buildSlideshowList if @options.addSlideshow?
508
+ if @options.generateFramePage?
509
+ buildFramePage
510
+ updateNavigationFrame
511
+ end
512
+ imageProcessing(progress)
513
+ return true
514
+ end
515
+
516
+ # This method will create an adhoc slideshow in the
517
+ # imageOutputPath without copying any image
518
+ # Just for testing issues
519
+ # Works fine if all the images allready have appropriate size
520
+ def onTheFlySlideshow
521
+ unless File.directory?(File.join(outputPath, subDir))
522
+ createSubdir
523
+ end
524
+ copyTemplates(['slideshow.htm', 'slideshow.js'], imageOutputPath)
525
+ buildSlideshowList(@inputDir)
526
+ return File.join(imageOutputPath, 'slideshow.htm')
527
+ end
528
+
529
+ protected
530
+
531
+ ##
532
+ # Overwrite this hook method to add image processing
533
+ # to html genmeration
534
+ def imageProcessing(&block)
535
+ end
536
+
537
+ ##
538
+ # Service which migt be useful if no client is set
539
+ def runCommand(commandline, workingDir)
540
+ inPath(workingDir) { `#{commandline}` }
541
+ end
542
+ end
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/ruby
2
+ #$Id: file_info.rb 181 2007-12-12 23:33:46Z Sascha $
3
+
4
+ # This file is used to compute byte sizes of
5
+ # a set of given files and directories.
6
+ # The size of directories is computed recursively.
7
+ class UploadInfo
8
+ attr_reader(:bytes, :numFiles, :bytesHash)
9
+
10
+ def initialize(filesWithPath)
11
+ @bytesHash = Hash.new
12
+ @bytes = 0
13
+ @numFiles = 0
14
+ add(filesWithPath)
15
+ end
16
+
17
+ private
18
+
19
+ def add(filesWithPath)
20
+ filesWithPath.each do |fileWithPath|
21
+ unless @bytesHash.has_key?(fileWithPath)
22
+ if File.directory?(fileWithPath)
23
+ subfiles = Dir.entries(fileWithPath).reject { |e|
24
+ e =~ /^\./
25
+ }
26
+ subfilesWithPath = subfiles.collect { |e|
27
+ FilePath.join(fileWithPath, e)
28
+ }
29
+ add(subfilesWithPath)
30
+ else
31
+ fileSize = File.size(fileWithPath)
32
+ @bytesHash[fileWithPath] = fileSize
33
+ @bytes = @bytes + fileSize
34
+ @numFiles = @numFiles + 1
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/ruby
2
+ #$Id: version.rb 195 2008-05-29 21:32:40Z Sascha $
3
+
4
+ # Provide release information for Piggy.
5
+ module PiggyVersion
6
+ def PiggyVersion.versionString
7
+ '0.4.2-2'
8
+ end
9
+ def PiggyVersion.copyrightString
10
+ 'Copyright (C) 2008 Sascha D�rdelmann'
11
+ end
12
+ def PiggyVersion.developmentStatus
13
+ 'alpha'
14
+ end
15
+ def PiggyVersion.displayString
16
+ "#{PiggyVersion.versionString} (#{PiggyVersion.developmentStatus})"
17
+ end
18
+ end