Merge lp:~ryan-c-ahearn/backintime/command_line_interface into lp:backintime/1.0

Proposed by Ryan Ahearn
Status: Needs review
Proposed branch: lp:~ryan-c-ahearn/backintime/command_line_interface
Merge into: lp:backintime/1.0
Diff against target: 1954 lines (+1735/-5)
30 files modified
.bzrignore (+2/-0)
AUTHORS (+1/-0)
README (+12/-0)
cli/Makefile.template (+25/-0)
cli/backintime-config (+27/-0)
cli/backintime-restore (+27/-0)
cli/bitconfig.py (+142/-0)
cli/bitrestore.py (+131/-0)
cli/configure (+12/-0)
cli/copywidget.py (+67/-0)
cli/debian_specific/control (+10/-0)
cli/debian_specific/control.source (+14/-0)
cli/debian_specific/postrm (+3/-0)
cli/debian_specific/rules (+50/-0)
cli/excludewidget.py (+118/-0)
cli/expertwidget.py (+47/-0)
cli/generalwidget.py (+93/-0)
cli/includewidget.py (+118/-0)
cli/optionswidget.py (+45/-0)
cli/profilewidget.py (+162/-0)
cli/removesnapshot.py (+51/-0)
cli/removewidget.py (+114/-0)
cli/restorewidget.py (+107/-0)
cli/snapshotname.py (+52/-0)
cli/snapshotswidget.py (+158/-0)
cli/viewerwidget.py (+132/-0)
common/backintime.py (+1/-1)
common/logger.py (+0/-3)
makedeb.sh (+1/-1)
updateversion.sh (+13/-0)
To merge this branch: bzr merge lp:~ryan-c-ahearn/backintime/command_line_interface
Reviewer Review Type Date Requested Status
Back In Time Team Pending
Review via email: mp+20422@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Ryan Ahearn (ryan-c-ahearn) wrote :

Here's my first cut of a command line interface for back in time configuration and restore.

It's not the prettiest interface right now, but it seems functionally solid. All of the displayed strings have the gettext call around them, but I don't speak any other languages so I have left the language files alone.

I tried to leave common alone as much as possible, but I had to suppress a couple of print calls to clean up the display when a user kicked off taking a snapshot from inside of backintime-restore.

Let me know what you think.

691. By Ryan Ahearn

Fixed bug in setting the hour to run backintime for daily/weekly/monthly backups

Unmerged revisions

691. By Ryan Ahearn

Fixed bug in setting the hour to run backintime for daily/weekly/monthly backups

690. By Ryan Ahearn

Added gettext calls to all strings that will be displayed to the user

689. By Ryan Ahearn

Added cli entries to the updateversion script

688. By Ryan Ahearn

Added myself to the AUTHORS file

687. By Ryan Ahearn

Added sections on cli to the README

686. By Ryan Ahearn

Added simple packaging files for backintime-cli

685. By Ryan Ahearn

Uncommented the man page install lines from Makefile.template to get them installed

684. By Ryan Ahearn

Added backintime-config and backintime-restore man pages

683. By Ryan Ahearn

Can now set the backup time for daily, weekly, and monthly backups

682. By Ryan Ahearn

Added ability to name and delete snapshots from restore window

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file '.bzrignore'
--- .bzrignore 1970-01-01 00:00:00 +0000
+++ .bzrignore 2010-03-02 06:06:17 +0000
@@ -0,0 +1,2 @@
1Makefile
2common/po/*.mo
03
=== modified file 'AUTHORS'
--- AUTHORS 2009-11-06 13:00:42 +0000
+++ AUTHORS 2010-03-02 06:06:17 +0000
@@ -1,3 +1,4 @@
1Oprea Dan (<dan@le-web.org>)1Oprea Dan (<dan@le-web.org>)
2Bart de Koning (<bratdaking@gmail.com>)2Bart de Koning (<bratdaking@gmail.com>)
3Richard Bailey (<rmjb@mail.com>)3Richard Bailey (<rmjb@mail.com>)
4Ryan Ahearn (<ryan.c.ahearn@gmail.com>)
45
=== modified file 'README'
--- README 2009-11-02 13:52:00 +0000
+++ README 2010-03-02 06:06:17 +0000
@@ -39,6 +39,12 @@
39 sudo dpkg -i backintime-common-<version>.deb39 sudo dpkg -i backintime-common-<version>.deb
40 sudo dpkg -i backintime-kde4-<version>.deb40 sudo dpkg -i backintime-kde4-<version>.deb
4141
42 Command Line Interface: (python-urwid >= 0.9.9)
43
44 ./makedeb.sh
45 sudo dpkg -i backintime-common-<version>.deb
46 sudo dpkg -i backintime-cli-<version>.deb
47
42 NOTE:48 NOTE:
43 Ubuntu 8.04: to install KDE4 4.1 check this link:49 Ubuntu 8.04: to install KDE4 4.1 check this link:
44 http://news.softpedia.com/news/How-To-Install-KDE-4-1-On-Ubuntu-8-04-91034.shtml50 http://news.softpedia.com/news/How-To-Install-KDE-4-1-On-Ubuntu-8-04-91034.shtml
@@ -50,6 +56,12 @@
50 ./configure56 ./configure
51 make57 make
52 sudo make install58 sudo make install
59
60 Command Line Interface (dependencies: python-urwid (> 0.9.9)):
61 cd cli
62 ./configure
63 make
64 sudo make install
5365
54 GNOME (dependencies: python-glade2, python-gnome2, meld):66 GNOME (dependencies: python-glade2, python-gnome2, meld):
55 cd gnome67 cd gnome
5668
=== added directory 'cli'
=== added file 'cli/Makefile.template'
--- cli/Makefile.template 1970-01-01 00:00:00 +0000
+++ cli/Makefile.template 2010-03-02 06:06:17 +0000
@@ -0,0 +1,25 @@
1PREFIX=/usr
2DEST=$(DESTDIR)$(PREFIX)
3
4all:
5
6clean:
7
8install:
9 #install python
10 install -d $(DEST)/share/backintime/cli
11 install --mode=644 *.py $(DEST)/share/backintime/cli
12
13 #install copyright file
14 install -d $(DEST)/share/doc/backintime-cli
15 install --mode=644 ../common/debian_specific/copyright $(DEST)/share/doc/backintime-cli
16
17 #install man file(s)
18 install -d $(DEST)/share/man/man1
19 install --mode=644 man/C/*.gz $(DEST)/share/man/man1
20
21 #install application
22 install -d $(DEST)/bin
23 install backintime-config $(DEST)/bin
24 install backintime-restore $(DEST)/bin
25
026
=== added file 'cli/backintime-config'
--- cli/backintime-config 1970-01-01 00:00:00 +0000
+++ cli/backintime-config 2010-03-02 06:06:17 +0000
@@ -0,0 +1,27 @@
1#!/bin/sh
2
3# Back In Time
4# Copyright (C) 2010 Ryan Ahearn
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program; if not, write to the Free Software Foundation, Inc.,
18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20if [ -f bitconfig.py ]; then
21 APP_PATH="."
22else
23 APP_PATH="/usr/share/backintime/cli"
24fi
25
26python ${APP_PATH}/bitconfig.py "$@"
27
028
=== added file 'cli/backintime-restore'
--- cli/backintime-restore 1970-01-01 00:00:00 +0000
+++ cli/backintime-restore 2010-03-02 06:06:17 +0000
@@ -0,0 +1,27 @@
1#!/bin/sh
2
3# Back In Time
4# Copyright (C) 2010 Ryan Ahearn
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program; if not, write to the Free Software Foundation, Inc.,
18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20if [ -f bitrestore.py ]; then
21 APP_PATH="."
22else
23 APP_PATH="/usr/share/backintime/cli"
24fi
25
26python ${APP_PATH}/bitrestore.py "$@"
27
028
=== added file 'cli/bitconfig.py'
--- cli/bitconfig.py 1970-01-01 00:00:00 +0000
+++ cli/bitconfig.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,142 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
19import os.path
20import sys
21import urwid
22import gettext
23
24sys.path = [os.path.join( os.path.dirname( os.path.abspath( os.path.dirname( __file__ ) ) ), 'common' )] + sys.path
25
26import backintime
27import config
28import logger
29import guiapplicationinstance
30import profilewidget
31import generalwidget
32import includewidget
33import excludewidget
34import removewidget
35import optionswidget
36import expertwidget
37
38_=gettext.gettext
39
40class MainWindow(object):
41
42 def __init__( self, config ):
43 self._config = config
44
45 self._header = _('Back in Time Configuration') + '. ' + _('F6 exits')
46 setting_sections = [ "Profiles", "General", "Include", "Exclude", "Auto-remove", "Options", "Expert Options" ]
47 self._listbox_content = [
48 urwid.Divider(), # position 0
49 urwid.Text( _("Profile") + ": " + config.get_profile_name() ), # position 1
50 urwid.Divider(), # position 2
51 urwid.GridFlow( [ urwid.AttrWrap( urwid.Button( _(txt), self.sections_button_press, txt ), 'button', 'button_focus' ) for txt in setting_sections ],
52 18, 2, 1, 'center' ), # position 3
53 urwid.Divider(), # position 4
54 profilewidget.ProfileWidget( self, config ), # position 5
55 ]
56
57 def sections_button_press( self, button, user_data ):
58 if user_data == 'Profiles':
59 widget = profilewidget.ProfileWidget( self, self._config )
60 elif user_data == 'General':
61 widget = generalwidget.GeneralWidget( self, self._config )
62 elif user_data == 'Include':
63 widget = includewidget.IncludeWidget( self, self._config )
64 elif user_data == 'Exclude':
65 widget = excludewidget.ExcludeWidget( self, self._config )
66 elif user_data == 'Auto-remove':
67 widget = removewidget.RemoveWidget( self._config )
68 elif user_data == 'Options':
69 widget = optionswidget.OptionsWidget( self._config )
70 elif user_data == 'Expert Options':
71 widget = expertwidget.ExpertOptionsWidget( self._config )
72 self.update_content( widget, 5 )
73
74 def show( self ):
75 header = urwid.AttrWrap( urwid.Text( self._header, align='center' ), 'header' )
76 self._content = urwid.SimpleListWalker( self._listbox_content )
77 self._listbox = urwid.ListBox( self._content )
78 frame = urwid.Frame( urwid.AttrWrap( self._listbox, 'body' ), header=header )
79
80 palette = [
81 ( 'body', 'black', 'light gray', 'standout' ),
82 ( 'error', 'dark red', 'light gray', 'bold' ),
83 ( 'header', 'white', 'dark red', 'bold' ),
84 ( 'button', 'black', 'dark cyan' ),
85 ( 'button_focus', 'white', 'dark blue', 'bold' ),
86 ( 'edit_box', 'light gray', 'dark blue' ),
87 ( 'edit_focus', 'white', 'dark blue', 'bold' )
88 ]
89
90 urwid.MainLoop( frame, palette, unhandled_input=self.unhandled_input ).run()
91
92 def update_content( self, widget, position ):
93 self._content[position] = widget
94
95 def update_profile_name( self ):
96 self.update_content( urwid.Text( _('Profile') + ': ' + self._config.get_profile_name() ), 1 )
97
98 def unhandled_input( self, key ):
99 if key == 'f6':
100 self.on_close()
101
102 def on_close( self ):
103 self.update_content( ConfirmSave( self._config ), 5 )
104
105class ConfirmSave(urwid.WidgetWrap):
106
107 def __init__( self, config ):
108 self._config = config
109
110 pile_list = [
111 urwid.Padding( urwid.Text( _('Save configuration?') ), 'center' ),
112 urwid.Divider(),
113 urwid.GridFlow( [
114 urwid.AttrWrap( urwid.Button( _('Yes'), self.save ), 'button', 'button_focus' ),
115 urwid.AttrWrap( urwid.Button( _('No'), self.close ), 'button', 'button_focus' )
116 ], 10, 2, 1, 'center' )
117 ]
118
119 display_widget = urwid.Pile( pile_list )
120 urwid.WidgetWrap.__init__( self, display_widget )
121
122 def save( self, button ):
123 self._config.save()
124 self._config.setup_cron()
125 self.close()
126
127 def close( self, button=None ):
128 raise urwid.ExitMainLoop()
129
130if __name__ == '__main__':
131 cfg = backintime.start_app( 'backintime-config' )
132 raise_cmd = ''
133 if len( sys.argv ) > 1:
134 raise_cmd = '\n'.join( sys.argv[ 1 : ] )
135 app_instance = guiapplicationinstance.GUIApplicationInstance( cfg.get_app_instance_file(), raise_cmd )
136
137 logger.openlog()
138 main_window = MainWindow( cfg )
139 main_window.show()
140 logger.closelog()
141
142 app_instance.exit_application()
0143
=== added file 'cli/bitrestore.py'
--- cli/bitrestore.py 1970-01-01 00:00:00 +0000
+++ cli/bitrestore.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,131 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
19import os.path
20import sys
21import urwid
22import gettext
23
24sys.path = [os.path.join( os.path.dirname( os.path.abspath( os.path.dirname( __file__ ) ) ), 'common' )] + sys.path
25
26import backintime
27import config
28import logger
29import guiapplicationinstance
30import profilewidget
31import restorewidget
32import removesnapshot
33import snapshotname
34
35_=gettext.gettext
36
37class MainWindow(object):
38
39 def __init__( self, config ):
40 self._config = config
41 self.selected_snapshot = ''
42 self.selected_snapshot_name = ''
43 self.current_directory = config.get_str_value( 'cli.last_path', '/' )
44 self.show_hidden = False
45
46 self._header = _('Back in Time Restore Utility') + '. ' + _('F6 exits')
47 self._profile_button = urwid.Button( config.get_profile_name(), self.change_profile )
48 buttons = [ 'Take Snapshot', 'Update Snapshots', 'Snapshot Name', 'Remove Snapshot' ]
49 self._listbox_content = [
50 urwid.Divider(), # position 0
51 urwid.AttrWrap( self._profile_button, 'button', 'button_focus' ), # position 1
52 urwid.Divider(), # position 2
53 urwid.GridFlow( [ urwid.AttrWrap( urwid.Button( _(txt), self.button_press, txt ), 'button', 'button_focus' ) for txt in buttons ],
54 20, 2, 1, 'center' ), # position 3
55 urwid.Divider(), # position 4
56 restorewidget.RestoreWidget( self, config ), # position 5
57 ]
58
59 def change_profile( self, button ):
60 self.update_content( profilewidget.ProfileWidget( self, self._config, False ), 5 )
61
62 def button_press( self, button, user_data ):
63 if user_data == 'Take Snapshot':
64 backintime.take_snapshot_now_async( self._config )
65 elif user_data == 'Update Snapshots':
66 self.update_content( restorewidget.RestoreWidget( self, self._config ), 5 )
67 elif user_data == 'Snapshot Name' and self.selected_snapshot != '':
68 self.update_content( snapshotname.SnapshotName( self, self._config ), 5 )
69 elif user_data == 'Remove Snapshot' and self.selected_snapshot != '':
70 self.update_content( removesnapshot.RemoveSnapshot( self, self._config ), 5 )
71
72 def show( self ):
73 header = urwid.AttrWrap( urwid.Text( self._header, align='center' ), 'header' )
74 self._content = urwid.SimpleListWalker( self._listbox_content )
75 self._listbox = urwid.ListBox( self._content )
76 frame = urwid.Frame( urwid.AttrWrap( self._listbox, 'body' ), header=header )
77
78 palette = [
79 ( 'body', 'black', 'light gray', 'standout' ),
80 ( 'error', 'dark red', 'light gray', 'bold' ),
81 ( 'header', 'white', 'dark red', 'bold' ),
82 ( 'button', 'black', 'dark cyan' ),
83 ( 'button_focus', 'white', 'dark blue', 'bold' ),
84 ( 'edit_box', 'light gray', 'dark blue' ),
85 ( 'edit_focus', 'white', 'dark blue', 'bold' )
86 ]
87
88 self.main_loop = urwid.MainLoop( frame, palette, unhandled_input=self.unhandled_input )
89 self.main_loop.run()
90
91 def update_content( self, widget, position ):
92 self._content[position] = widget
93
94 def update_profile_name( self ):
95 self._profile_button.set_label( self._config.get_profile_name() )
96 self.selected_snapshot = ''
97 self.update_content( restorewidget.RestoreWidget( self, self._config ), 5 )
98
99 def update_current_directory( self, new_directory ):
100 self.current_directory = new_directory
101 self._config.set_str_value( 'cli.last_path', new_directory )
102 self.update_content( restorewidget.RestoreWidget( self, self._config ), 5 )
103
104 def is_selected_snapshot( self, snapshot ):
105 if self.selected_snapshot == snapshot:
106 return True
107 else:
108 return False
109
110 def unhandled_input( self, key ):
111 if key == 'f6':
112 self.on_close()
113
114 def on_close( self ):
115 self._config.save()
116 raise urwid.ExitMainLoop()
117
118
119if __name__ == '__main__':
120 cfg = backintime.start_app( 'backintime-restore' )
121 raise_cmd = ''
122 if len( sys.argv ) > 1:
123 raise_cmd = '\n'.join( sys.argv[ 1 : ] )
124 app_instance = guiapplicationinstance.GUIApplicationInstance( cfg.get_app_instance_file(), raise_cmd )
125
126 logger.openlog()
127 main_window = MainWindow( cfg )
128 main_window.show()
129 logger.closelog()
130
131 app_instance.exit_application()
0132
=== added file 'cli/configure'
--- cli/configure 1970-01-01 00:00:00 +0000
+++ cli/configure 2010-03-02 06:06:17 +0000
@@ -0,0 +1,12 @@
1#!/bin/bash
2
3if [ -e Makefile ]; then
4 rm Makefile;
5fi
6
7cp Makefile.template Makefile
8
9echo "All OK. Now run:"
10echo " make"
11echo " sudo make install"
12
013
=== added file 'cli/copywidget.py'
--- cli/copywidget.py 1970-01-01 00:00:00 +0000
+++ cli/copywidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,67 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
19import os.path
20import shutil
21import urwid
22import gettext
23
24import logger
25import restorewidget
26
27_=gettext.gettext
28
29class CopyWidget(urwid.WidgetWrap):
30
31 def __init__( self, main_win, config, to_copy ):
32 self._main_win = main_win
33 self._config = config
34 self._to_copy = to_copy
35
36 self._edit_box = urwid.Edit(( 'body', _('Enter destination') + ': ' ))
37 pile_list = [
38 urwid.AttrWrap( self._edit_box, 'edit_box', 'edit_focus' ),
39 urwid.Divider(),
40 urwid.GridFlow( [
41 urwid.AttrWrap( urwid.Button( _('OK'), self.ok_pressed ), 'button', 'button_focus' ),
42 urwid.AttrWrap( urwid.Button( _('Cancel'), self.go_home ), 'button', 'button_focus' )
43 ], 10, 2, 1, 'right' )
44 ]
45
46 display_widget = urwid.Pile( pile_list )
47 urwid.WidgetWrap.__init__( self, display_widget )
48
49 def ok_pressed( self, button ):
50 destination = self._edit_box.get_edit_text().strip()
51 logger.info( 'copying %s to %s' % ( self._to_copy, destination ) )
52 if os.path.isdir( self._to_copy ):
53 self._copy_directory( destination )
54 else:
55 self._copy_file( destination )
56 self.go_home()
57
58 def _copy_directory( self, destination ):
59 while os.path.exists( destination ):
60 destination = os.path.join( destination, os.path.basename( self._to_copy ) )
61 shutil.copytree( self._to_copy, destination, True )
62
63 def _copy_file( self, destination ):
64 shutil.copy2( self._to_copy, destination )
65
66 def go_home( self, button=None ):
67 self._main_win.update_content( restorewidget.RestoreWidget( self._main_win, self._config ), 5 )
068
=== added directory 'cli/debian_specific'
=== added file 'cli/debian_specific/control'
--- cli/debian_specific/control 1970-01-01 00:00:00 +0000
+++ cli/debian_specific/control 2010-03-02 06:06:17 +0000
@@ -0,0 +1,10 @@
1Package: backintime-cli
2Version: 0.9.99.18
3Priority: optional
4Section: utils
5Maintainer: BIT Team <bit-team@lists.launchpad.net>
6Architecture: all
7Homepage: http://backintime.le-web.org
8Depends: python-urwid (>> 0.9.9), backintime-common (= 0.9.99.18)
9Description: Simple backup system for command line use.
10 This is a command line interface frontend for backintime-common.
011
=== added file 'cli/debian_specific/control.source'
--- cli/debian_specific/control.source 1970-01-01 00:00:00 +0000
+++ cli/debian_specific/control.source 2010-03-02 06:06:17 +0000
@@ -0,0 +1,14 @@
1Source: backintime-cli
2Maintainer: BIT Team <bit-team@lists.launchpad.net>
3Section: utils
4Priority: optional
5Standards-Version: 3.7.3
6Homepage: http://backintime.le-web.org
7
8Package: backintime-cli
9Architecture: all
10Section: utils
11Priority: optional
12Depends: python-urwid (>> 0.9.9), backintime-common (= 0.9.99.18)
13Description: Simple backup system for command line use.
14 This is a command line interface frontend for backintime-common.
015
=== added file 'cli/debian_specific/postrm'
--- cli/debian_specific/postrm 1970-01-01 00:00:00 +0000
+++ cli/debian_specific/postrm 2010-03-02 06:06:17 +0000
@@ -0,0 +1,3 @@
1#!/bin/sh
2rm -rf /usr/share/backintime/cli/*.pyc
3exit 0
04
=== added file 'cli/debian_specific/rules'
--- cli/debian_specific/rules 1970-01-01 00:00:00 +0000
+++ cli/debian_specific/rules 2010-03-02 06:06:17 +0000
@@ -0,0 +1,50 @@
1#!/usr/bin/make -f
2
3package = backintime-cli
4
5clean:
6 dh_testdir
7 dh_clean
8 rm -f build
9
10install: build
11 #install python
12 #dh_installdirs /usr/share/backintime/gnome
13 dh_install *.py /usr/share/backintime/cli
14
15 #install copyright file
16 #dh_installdirs /usr/share/doc/backintime-gnome
17 dh_install debian/copyright /usr/share/doc/backintime-cli
18
19 #install man file(s)
20 #dh_installdirs /usr/share/man/man1
21 dh_install man/C/*.gz /usr/share/man/man1
22
23 #install application
24 #dh_installdirs /usr/bin
25 dh_install backintime-config /usr/bin
26 dh_install backintime-restore /usr/bin
27
28build:
29 touch build
30
31binary-indep: install
32 dh_testdir -i
33 dh_testroot -i
34 #dh_installdocs -i NEWS
35 #dh_installchangelogs -i ChangeLog
36 #dh_strip -i
37 #dh_compress -i
38 dh_fixperms -i
39 dh_installdeb -i
40 #dh_shlibdeps -i
41 dh_gencontrol -i
42 dh_md5sums -i
43 dh_builddeb -i
44
45binary-arch: install
46
47binary: binary-indep
48
49.PHONY: binary binary-arch binary-indep clean
50
051
=== added file 'cli/excludewidget.py'
--- cli/excludewidget.py 1970-01-01 00:00:00 +0000
+++ cli/excludewidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,118 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18import urwid
19import gettext
20
21import logger
22
23_=gettext.gettext
24
25class ExcludeWidget(urwid.WidgetWrap):
26
27 def __init__( self, main_win, config ):
28 self._main_win = main_win
29 self._config = config
30 self._to_delete = None
31
32 all_patterns = config.get_exclude_patterns()
33 if len( all_patterns ) == 0:
34 chooser = urwid.Divider()
35 else:
36 excluded_patterns = []
37 for pattern in all_patterns:
38 urwid.RadioButton( excluded_patterns, pattern, False, self.pattern_selected )
39 chooser = urwid.Pile( excluded_patterns )
40
41 pile_list = [
42 urwid.Text( _('Patterns, files or folders') ),
43 urwid.Divider(),
44 chooser,
45 urwid.Divider(),
46 urwid.GridFlow([
47 urwid.AttrWrap( urwid.Button( _('Add'), self.add_pattern ), 'button', 'button_focus' ),
48 urwid.AttrWrap( urwid.Button( _('Delete'), self.delete_pattern ), 'button', 'button_focus' ),
49 ], 10, 2, 1, 'center' )
50 ]
51
52 display_widget = urwid.Pile( pile_list )
53 urwid.WidgetWrap.__init__( self, display_widget )
54
55 def pattern_selected( self, button, new_state ):
56 if new_state:
57 self._to_delete = button.get_label()
58
59 def add_pattern( self, button ):
60 self._main_win.update_content( AddExcludeWidget( self._main_win, self._config ), 5 )
61
62 def delete_pattern( self, button ):
63 if self._to_delete is not None:
64 self._main_win.update_content( DeleteExcludeWidget( self._main_win, self._config, self._to_delete ), 5 )
65
66 def go_to_exclude_patterns( self, button=None ):
67 self._main_win.update_content( ExcludeWidget( self._main_win, self._config ), 5 )
68
69
70class AddExcludeWidget(ExcludeWidget):
71
72 def __init__( self, main_win, config ):
73 self._main_win = main_win
74 self._config = config
75
76 self._edit_box = urwid.Edit(( 'body', _('Enter pattern, file, or folder to exclude') + ': ' ))
77 pile_list = [
78 urwid.AttrWrap( self._edit_box, 'edit_box', 'edit_focus' ),
79 urwid.Divider(),
80 urwid.GridFlow( [
81 urwid.AttrWrap( urwid.Button( _('OK'), self.ok_pressed ), 'button', 'button_focus' ),
82 urwid.AttrWrap( urwid.Button( _('Cancel'), self.go_to_exclude_patterns ), 'button', 'button_focus' )
83 ], 10, 2, 1, 'right' )
84 ]
85
86 display_widget = urwid.Pile( pile_list )
87 urwid.WidgetWrap.__init__( self, display_widget )
88
89 def ok_pressed( self, button ):
90 all_patterns = self._config.get_exclude_patterns()
91 all_patterns.append( self._edit_box.get_edit_text().strip() )
92 self._config.set_exclude_patterns( all_patterns )
93 self.go_to_exclude_patterns()
94
95class DeleteExcludeWidget(ExcludeWidget):
96
97 def __init__( self, main_win, config, to_delete ):
98 self._main_win = main_win
99 self._config = config
100 self._to_delete = to_delete
101
102 pile_list = [
103 urwid.Text( _('Are you sure you want to remove') + ' "' + to_delete + '" ' + _('from the excluded patterns?') ),
104 urwid.Divider(),
105 urwid.GridFlow( [
106 urwid.AttrWrap( urwid.Button( _('Yes'), self.yes_pressed ), 'button', 'button_focus' ),
107 urwid.AttrWrap( urwid.Button( _('No'), self.go_to_exclude_patterns ), 'button', 'button_focus' )
108 ], 10, 2, 1, 'right' )
109 ]
110
111 display_widget = urwid.Pile( pile_list )
112 urwid.WidgetWrap.__init__( self, display_widget )
113
114 def yes_pressed( self, button ):
115 all_patterns = self._config.get_exclude_patterns()
116 all_patterns.remove( self._to_delete )
117 self._config.set_exclude_patterns( all_patterns )
118 self.go_to_exclude_patterns()
0119
=== added file 'cli/expertwidget.py'
--- cli/expertwidget.py 1970-01-01 00:00:00 +0000
+++ cli/expertwidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,47 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18import urwid
19import gettext
20
21import logger
22
23_=gettext.gettext
24
25class ExpertOptionsWidget(urwid.WidgetWrap):
26
27 def __init__( self, config ):
28 self._config = config
29
30 pile_list = [
31 urwid.Padding( urwid.Text(( 'error', _('Change these options only if you really know what you are doing!') )), 'center' ),
32 urwid.Divider(),
33 urwid.CheckBox( _("Run 'nice' as cron job (default: enabled)"), config.is_run_nice_from_cron_enabled(), on_state_change=self.flip_nice_cron ),
34 urwid.CheckBox( _("Run 'ionice' as cron job (default: enabled)"), config.is_run_ionice_from_cron_enabled(), on_state_change=self.flip_ionice_cron ),
35 urwid.CheckBox( _("Run 'ionice' when taking a manual snapshot (default: disabled)"), config.is_run_ionice_from_user_enabled(), on_state_change=self.flip_ionice_user )
36 ]
37 display_widget = urwid.Pile( pile_list )
38 urwid.WidgetWrap.__init__( self, display_widget )
39
40 def flip_nice_cron( self, check_box, new_state ):
41 self._config.set_run_nice_from_cron_enabled( new_state )
42
43 def flip_ionice_cron( self, check_box, new_state ):
44 self._config.set_run_ionice_from_cron_enabled( new_state )
45
46 def flip_ionice_user( self, check_box, new_state ):
47 self._config.set_run_ionice_from_user_enabled( new_state )
048
=== added file 'cli/generalwidget.py'
--- cli/generalwidget.py 1970-01-01 00:00:00 +0000
+++ cli/generalwidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,93 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18import urwid
19import gettext
20
21import logger
22
23_=gettext.gettext
24
25class GeneralWidget(urwid.WidgetWrap):
26
27 def __init__( self, main_win, config ):
28 self._config = config
29 self._main_win = main_win
30
31 backup_mode = config.get_automatic_backup_mode()
32 backup_modes = []
33 for key, value in sorted( config.AUTOMATIC_BACKUP_MODES.items() ):
34 if backup_mode == key:
35 urwid.RadioButton( backup_modes, value, True, self.schedule_changed, key )
36 else:
37 urwid.RadioButton( backup_modes, value, False, self.schedule_changed, key )
38 schedule_chooser = urwid.Pile( backup_modes )
39
40 location = urwid.Edit(( 'body', _('Where to save snapshots') + ': ' ), config.get_snapshots_path() )
41 urwid.connect_signal( location, 'change', self.location_changed )
42 self._error = urwid.Text( '' )
43 pile_list = [
44 urwid.AttrWrap( location, 'edit_box', 'edit_focus' ),
45 urwid.AttrWrap( self._error, 'error' ),
46 urwid.Divider()
47 ]
48
49 if backup_mode > config.HOUR:
50 # display chooser to set hour of the day to run the cron job
51 set_hour = config.get_automatic_backup_time() / 100
52 hour_choices = []
53 for i in range( 24 ):
54 if set_hour == i:
55 urwid.RadioButton( hour_choices, ( "%2d:00" % i ), True, self.time_changed, i )
56 else:
57 urwid.RadioButton( hour_choices, ( "%2d:00" % i ), False, self.time_changed, i )
58 hour_chooser = urwid.Pile( hour_choices )
59 pile_list.append(
60 urwid.Columns( [
61 urwid.Pile( [
62 urwid.Text( _('Schedule') ),
63 schedule_chooser
64 ] ),
65 urwid.Pile( [
66 urwid.Text( _('Hour') ),
67 hour_chooser
68 ] )
69 ], 1 )
70 )
71 else:
72 pile_list.extend( [
73 urwid.Text( _('Schedule') ),
74 schedule_chooser
75 ] )
76
77 display_widget = urwid.Pile( pile_list )
78 urwid.WidgetWrap.__init__( self, display_widget )
79
80 def schedule_changed( self, check_box, new_state, user_data ):
81 if new_state:
82 self._config.set_automatic_backup_mode( user_data )
83 self._main_win.update_content( GeneralWidget( self._main_win, self._config ), 5 )
84
85 def time_changed( self, check_box, new_state, user_data ):
86 if new_state:
87 self._config.set_automatic_backup_time( user_data * 100 )
88
89 def location_changed( self, edit, new_edit_text ):
90 if not self._config.set_snapshots_path( new_edit_text.strip() ):
91 self._error.set_text( _('Could not use this path, are you sure it exists and you have write access?') )
92 else:
93 self._error.set_text( '' )
094
=== added file 'cli/includewidget.py'
--- cli/includewidget.py 1970-01-01 00:00:00 +0000
+++ cli/includewidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,118 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18import urwid
19import gettext
20
21import logger
22
23_=gettext.gettext
24
25class IncludeWidget(urwid.WidgetWrap):
26
27 def __init__( self, main_win, config ):
28 self._main_win = main_win
29 self._config = config
30 self._to_delete = None
31
32 all_folders = config.get_include_folders()
33 if len( all_folders ) == 0:
34 chooser = urwid.Divider()
35 else:
36 included_folders = []
37 for folder in all_folders:
38 urwid.RadioButton( included_folders, folder, False, self.folder_selected )
39 chooser = urwid.Pile( included_folders )
40
41 pile_list = [
42 urwid.Text( _('Include Folders') ),
43 urwid.Divider(),
44 chooser,
45 urwid.Divider(),
46 urwid.GridFlow( [
47 urwid.AttrWrap( urwid.Button( _('Add'), self.add_folder ), 'button', 'button_focus' ),
48 urwid.AttrWrap( urwid.Button( _('Delete'), self.delete_folder ), 'button', 'button_focus' ),
49 ], 10, 2, 1, 'center' )
50 ]
51
52 display_widget = urwid.Pile( pile_list )
53 urwid.WidgetWrap.__init__( self, display_widget )
54
55 def folder_selected( self, button, new_state ):
56 if new_state:
57 self._to_delete = button.get_label()
58
59 def add_folder( self, button ):
60 self._main_win.update_content( AddIncludeWidget( self._main_win, self._config ), 5 )
61
62 def delete_folder( self, button ):
63 if self._to_delete is not None:
64 self._main_win.update_content( DeleteIncludeWidget( self._main_win, self._config, self._to_delete ), 5 )
65
66 def go_to_include_folders( self, button=None ):
67 self._main_win.update_content( IncludeWidget( self._main_win, self._config ), 5 )
68
69
70class AddIncludeWidget(IncludeWidget):
71
72 def __init__( self, main_win, config ):
73 self._main_win = main_win
74 self._config = config
75
76 self._edit_box = urwid.Edit(( 'body', _('Enter path for folder to backup') + ': ' ))
77 pile_list = [
78 urwid.AttrWrap( self._edit_box, 'edit_box', 'edit_focus' ),
79 urwid.Divider(),
80 urwid.GridFlow( [
81 urwid.AttrWrap( urwid.Button( _('OK'), self.ok_pressed ), 'button', 'button_focus' ),
82 urwid.AttrWrap( urwid.Button( _('Cancel'), self.go_to_include_folders ), 'button', 'button_focus' )
83 ], 10, 2, 1, 'right' )
84 ]
85
86 display_widget = urwid.Pile( pile_list )
87 urwid.WidgetWrap.__init__( self, display_widget )
88
89 def ok_pressed( self, button ):
90 all_folders = self._config.get_include_folders()
91 all_folders.append( self._edit_box.get_edit_text().strip() )
92 self._config.set_include_folders( all_folders )
93 self.go_to_include_folders()
94
95class DeleteIncludeWidget(IncludeWidget):
96
97 def __init__( self, main_win, config, to_delete ):
98 self._main_win = main_win
99 self._config = config
100 self._to_delete = to_delete
101
102 pile_list = [
103 urwid.Text( _('Are you sure you want to remove') + ' "' + to_delete + '" ' + _('from the backed up folders?') ),
104 urwid.Divider(),
105 urwid.GridFlow( [
106 urwid.AttrWrap( urwid.Button( _('Yes'), self.yes_pressed ), 'button', 'button_focus' ),
107 urwid.AttrWrap( urwid.Button( _('No'), self.go_to_include_folders ), 'button', 'button_focus' )
108 ], 10, 2, 1, 'right' )
109 ]
110
111 display_widget = urwid.Pile( pile_list )
112 urwid.WidgetWrap.__init__( self, display_widget )
113
114 def yes_pressed( self, button ):
115 all_folders = self._config.get_include_folders()
116 all_folders.remove( self._to_delete )
117 self._config.set_include_folders( all_folders )
118 self.go_to_include_folders()
0119
=== added directory 'cli/man'
=== added directory 'cli/man/C'
=== added file 'cli/man/C/backintime-config.1.gz'
1Binary files cli/man/C/backintime-config.1.gz 1970-01-01 00:00:00 +0000 and cli/man/C/backintime-config.1.gz 2010-03-02 06:06:18 +0000 differ120Binary files cli/man/C/backintime-config.1.gz 1970-01-01 00:00:00 +0000 and cli/man/C/backintime-config.1.gz 2010-03-02 06:06:18 +0000 differ
=== added file 'cli/man/C/backintime-restore.1.gz'
2Binary files cli/man/C/backintime-restore.1.gz 1970-01-01 00:00:00 +0000 and cli/man/C/backintime-restore.1.gz 2010-03-02 06:06:18 +0000 differ121Binary files cli/man/C/backintime-restore.1.gz 1970-01-01 00:00:00 +0000 and cli/man/C/backintime-restore.1.gz 2010-03-02 06:06:18 +0000 differ
=== added file 'cli/optionswidget.py'
--- cli/optionswidget.py 1970-01-01 00:00:00 +0000
+++ cli/optionswidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,45 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18import urwid
19import gettext
20
21import logger
22
23_=gettext.gettext
24
25class OptionsWidget(urwid.WidgetWrap):
26
27 def __init__( self, config ):
28 self._config = config
29
30 pile_list = [
31 urwid.CheckBox( _('Enable notifications'), config.is_notify_enabled(), on_state_change=self.flip_notify ),
32 urwid.CheckBox( _('Disable snapshots when on battery'), config.is_no_on_battery_enabled(), on_state_change=self.flip_battery ),
33 urwid.CheckBox( _('Backup files on restore'), config.is_backup_on_restore_enabled(), on_state_change=self.flip_backup_on_restore )
34 ]
35 display_widget = urwid.Pile( pile_list )
36 urwid.WidgetWrap.__init__( self, display_widget )
37
38 def flip_notify( self, check_box, new_state ):
39 self._config.set_notify_enabled( new_state )
40
41 def flip_battery( self, check_box, new_state ):
42 self._config.set_no_on_battery_enabled( new_state )
43
44 def flip_backup_on_restore( self, check_box, new_state ):
45 self._config.set_backup_on_restore( new_state )
046
=== added file 'cli/profilewidget.py'
--- cli/profilewidget.py 1970-01-01 00:00:00 +0000
+++ cli/profilewidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,162 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18import urwid
19import gettext
20
21import logger
22
23_=gettext.gettext
24
25class ProfileWidget(urwid.WidgetWrap):
26
27 def __init__( self, main_win, config, display_buttons=True ):
28 self._main_win = main_win
29 self._config = config
30
31 current_profile = config.get_current_profile()
32 profile_ids = config.get_profiles()
33 profiles = []
34 for profile_id in profile_ids:
35 profile_name = config.get_profile_name( profile_id )
36 if profile_id == current_profile:
37 urwid.RadioButton( profiles, profile_name, True, self.profile_changed, profile_id )
38 else:
39 urwid.RadioButton( profiles, profile_name, False, self.profile_changed, profile_id )
40 chooser = urwid.Pile( profiles )
41
42 pile_list = [
43 urwid.Text( _('Choose a profile') ),
44 urwid.Divider(),
45 chooser,
46 urwid.Divider()
47 ]
48
49 if display_buttons:
50 buttons = [
51 urwid.Button( _('Edit'), self.edit_profile ),
52 urwid.Button( _('New'), self.add_profile )
53 ]
54 if len( profile_ids ) > 1:
55 buttons.append( urwid.Button( _('Delete'), self.delete_profile ) )
56 pile_list.append( urwid.GridFlow( [ urwid.AttrWrap( button, 'button', 'button_focus' ) for button in buttons ], 10, 2, 1, 'center' ) )
57
58 display_widget = urwid.Pile( pile_list )
59 urwid.WidgetWrap.__init__( self, display_widget )
60
61 def profile_changed( self, button, new_state, user_data ):
62 if new_state:
63 self._config.set_current_profile( user_data )
64 self._main_win.update_profile_name()
65
66 def add_profile( self, button ):
67 self._main_win.update_content( AddProfileWidget( self._main_win, self._config ), 5 )
68
69 def edit_profile( self, button ):
70 self._main_win.update_content( EditProfileWidget( self._main_win, self._config ), 5 )
71
72 def delete_profile( self, button ):
73 self._main_win.update_content( DeleteProfileWidget( self._main_win, self._config ), 5 )
74
75 def go_to_profile_list( self, button=None ):
76 self._main_win.update_profile_name()
77 self._main_win.update_content( ProfileWidget( self._main_win, self._config ), 5 )
78
79
80class EditProfileWidget(ProfileWidget):
81
82 def __init__( self, main_win, config ):
83 self._main_win = main_win
84 self._config = config
85
86 self._edit_box = urwid.Edit(( 'body', _('Enter new name for profile') + ' ' + config.get_profile_name() + ': ' ))
87 self._error = urwid.Text( '' )
88 pile_list = [
89 urwid.AttrWrap( self._edit_box, 'edit_box', 'edit_focus' ),
90 urwid.AttrWrap( self._error, 'error' ),
91 urwid.Divider(),
92 urwid.GridFlow( [
93 urwid.AttrWrap( urwid.Button( _('OK'), self.ok_pressed ), 'button', 'button_focus' ),
94 urwid.AttrWrap( urwid.Button( _('Cancel'), self.go_to_profile_list ), 'button', 'button_focus' )
95 ], 10, 2, 1, 'right' )
96 ]
97
98 display_widget = urwid.Pile( pile_list )
99 urwid.WidgetWrap.__init__( self, display_widget )
100
101 def ok_pressed( self, button ):
102 name = self._edit_box.get_edit_text().strip()
103 if name == '':
104 self._error.set_text( _('Profile must be given a name') )
105 elif self._config.set_profile_name( name ):
106 self.go_to_profile_list()
107 else:
108 self._error.set_text( _('Profile name already exists, choose another') )
109
110
111class AddProfileWidget(ProfileWidget):
112
113 def __init__( self, main_win, config ):
114 self._main_win = main_win
115 self._config = config
116
117 self._edit_box = urwid.Edit(( 'body', _('Enter name for new profile') + ': ' ))
118 self._error = urwid.Text( '' )
119 pile_list = [
120 urwid.AttrWrap( self._edit_box, 'edit_box', 'edit_focus' ),
121 urwid.AttrWrap( self._error, 'error' ),
122 urwid.Divider(),
123 urwid.GridFlow([
124 urwid.AttrWrap( urwid.Button( _('OK'), self.ok_pressed ), 'button', 'button_focus' ),
125 urwid.AttrWrap( urwid.Button( _('Cancel'), self.go_to_profile_list ), 'button', 'button_focus' )
126 ], 10, 2, 1, 'right' )
127 ]
128
129 display_widget = urwid.Pile( pile_list )
130 urwid.WidgetWrap.__init__( self, display_widget )
131
132 def ok_pressed( self, button ):
133 name = self._edit_box.get_edit_text().strip()
134 if name == '':
135 self._error.set_text( _('Profile must be given a name') )
136 elif self._config.add_profile( name ):
137 self.go_to_profile_list()
138 else:
139 self._error.set_text( _('Profile name already exists, choose another') )
140
141
142class DeleteProfileWidget(ProfileWidget):
143
144 def __init__( self, main_win, config ):
145 self._main_win = main_win
146 self._config = config
147
148 pile_list = [
149 urwid.Text( _('Are You Sure you want to delete profile') + ' "' + config.get_profile_name() + '"' ),
150 urwid.Divider(),
151 urwid.GridFlow([
152 urwid.AttrWrap( urwid.Button( _('Yes'), self.yes_pressed ), 'button', 'button_focus' ),
153 urwid.AttrWrap( urwid.Button( _('No'), self.go_to_profile_list ), 'button', 'button_focus' )
154 ], 10, 2, 1, 'right' )
155 ]
156
157 display_widget = urwid.Pile( pile_list )
158 urwid.WidgetWrap.__init__( self, display_widget )
159
160 def yes_pressed( self, button ):
161 self._config.remove_profile()
162 self.go_to_profile_list()
0163
=== added file 'cli/removesnapshot.py'
--- cli/removesnapshot.py 1970-01-01 00:00:00 +0000
+++ cli/removesnapshot.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,51 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18import urwid
19import gettext
20
21import logger
22import restorewidget
23import snapshots
24
25_=gettext.gettext
26
27class RemoveSnapshot(urwid.WidgetWrap):
28
29 def __init__( self, main_win, config ):
30 self._main_win = main_win
31 self._config = config
32 self._snapshots = snapshots.Snapshots( config )
33
34 pile_list = [
35 urwid.Text( _('Are you sure you want to remove snapshot') + ' "' + main_win.selected_snapshot_name + '"' ),
36 urwid.Divider(),
37 urwid.GridFlow( [
38 urwid.AttrWrap( urwid.Button( _('Yes'), self.yes_pressed ), 'button', 'button_focus' ),
39 urwid.AttrWrap( urwid.Button( _('No'), self.go_home ), 'button', 'button_focus' )
40 ], 10, 2, 1, 'right' )
41 ]
42
43 display_widget = urwid.Pile( pile_list )
44 urwid.WidgetWrap.__init__( self, display_widget )
45
46 def yes_pressed( self, button ):
47 self._snapshots.remove_snapshot( self._main_win.selected_snapshot )
48 self.go_home()
49
50 def go_home( self, button=None ):
51 self._main_win.update_content( restorewidget.RestoreWidget( self._main_win, self._config ), 5 )
052
=== added file 'cli/removewidget.py'
--- cli/removewidget.py 1970-01-01 00:00:00 +0000
+++ cli/removewidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,114 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18import urwid
19import gettext
20
21import logger
22
23_=gettext.gettext
24
25class RemoveWidget(urwid.WidgetWrap):
26
27 def __init__( self, config ):
28 self._config = config
29
30 old_enabled, self._remove_old_value, self._remove_old_unit = config.get_remove_old_snapshots()
31 self._remove_old_enabled = urwid.CheckBox( _('Older than:'), old_enabled, on_state_change=self.flip_old_enabled )
32 remove_old_value_box = urwid.IntEdit( '', self._remove_old_value )
33 urwid.connect_signal( remove_old_value_box, 'change', self.remove_old_value_changed )
34 remove_units = []
35 for key, value in sorted( config.REMOVE_OLD_BACKUP_UNITS.items() ):
36 if self._remove_old_unit == key:
37 urwid.RadioButton( remove_units, value, True, self.remove_old_unit_changed, key )
38 else:
39 urwid.RadioButton( remove_units, value, False, self.remove_old_unit_changed, key )
40 remove_unit_chooser = urwid.Pile( remove_units )
41 age_columns = urwid.Columns( [
42 self._remove_old_enabled,
43 urwid.AttrWrap( remove_old_value_box, 'edit_box', 'edit_focus' ),
44 remove_unit_chooser
45 ], 1 )
46
47 space_enabled, self._free_space_value, self._free_space_unit = config.get_min_free_space()
48 self._free_space_enabled = urwid.CheckBox( _('If free space is less than:'), space_enabled, on_state_change=self.flip_free_space_enabled )
49 free_space_value_box = urwid.IntEdit( '', self._free_space_value )
50 urwid.connect_signal( free_space_value_box, 'change', self.free_space_value_changed )
51 free_space_units = []
52 for key, value in sorted( config.MIN_FREE_SPACE_UNITS.items() ):
53 if self._free_space_unit == key:
54 urwid.RadioButton( free_space_units, value, True, self.free_space_unit_changed, key )
55 else:
56 urwid.RadioButton( free_space_units, value, False, self.free_space_unit_changed, key )
57 space_unit_chooser = urwid.Pile( free_space_units )
58 space_columns = urwid.Columns( [
59 self._free_space_enabled,
60 urwid.AttrWrap( free_space_value_box, 'edit_box', 'edit_focus' ),
61 space_unit_chooser
62 ], 1 )
63
64 pile_list = [
65 age_columns,
66 urwid.Divider(),
67 space_columns,
68 urwid.Divider(),
69 urwid.CheckBox( _('Smart remove'), config.get_smart_remove(), on_state_change=self.flip_smart_remove ),
70 urwid.Padding( urwid.Text( _('- keep all snapshots from today and yesterday') ), left=4 ),
71 urwid.Padding( urwid.Text( _('- keep one snapshot for the last week and one for two weeks ago') ), left=4 ),
72 urwid.Padding( urwid.Text( _('- keep one snapshot per month for all previous months of this year and all months of the last year') ), left=4 ),
73 urwid.Padding( urwid.Text( _('- keep one snapshot per year for all other years') ), left=4 ),
74 urwid.Divider(),
75 urwid.CheckBox( _("Don't remove named snapshots"), config.get_dont_remove_named_snapshots(), on_state_change=self.flip_remove_named )
76 ]
77 display_widget = urwid.Pile( pile_list )
78 urwid.WidgetWrap.__init__( self, display_widget )
79
80 def flip_remove_named( self, check_box, new_state ):
81 self._config.set_dont_remove_named_snapshots( new_state )
82
83 def flip_smart_remove( self, check_box, new_state ):
84 self._config.set_smart_remove( new_state )
85
86 def flip_free_space_enabled( self, check_box, new_state ):
87 self._config.set_min_free_space( new_state, self._free_space_value, self._free_space_unit )
88
89 def free_space_value_changed( self, edit, new_edit_text ):
90 if new_edit_text == '':
91 self._free_space_value = 0
92 else:
93 self._free_space_value = new_edit_text.strip()
94 self._config.set_min_free_space( self._free_space_enabled.get_state(), self._free_space_value, self._free_space_unit )
95
96 def free_space_unit_changed( self, check_box, new_state, user_data ):
97 if new_state:
98 self._free_space_unit = user_data
99 self._config.set_min_free_space( self._free_space_enabled.get_state(), self._free_space_value, self._free_space_unit )
100
101 def flip_old_enabled( self, check_box, new_state ):
102 self._config.set_remove_old_snapshots( new_state, self._remove_old_value, self._remove_old_unit )
103
104 def remove_old_value_changed( self, edit, new_edit_text ):
105 if new_edit_text == '':
106 self._remove_old_value = 0
107 else:
108 self._remove_old_value = new_edit_text.strip()
109 self._config.set_remove_old_snapshots( self._remove_old_enabled.get_state(), self._remove_old_value, self._remove_old_unit )
110
111 def remove_old_unit_changed( self, check_box, new_state, user_data ):
112 if new_state:
113 self._remove_old_unit = user_data
114 self._config.set_remove_old_snapshots( self._remove_old_enabled.get_state(), self._remove_old_value, self._remove_old_unit )
0115
=== added file 'cli/restorewidget.py'
--- cli/restorewidget.py 1970-01-01 00:00:00 +0000
+++ cli/restorewidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,107 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
19import urwid
20import datetime
21import gettext
22
23import logger
24import snapshots
25import viewerwidget
26
27_=gettext.gettext
28
29class RestoreWidget(urwid.WidgetWrap):
30
31 def __init__( self, main_win, config ):
32 self._main_win = main_win
33 self._config = config
34
35 self._snapshots = snapshots.Snapshots( config )
36 snapshots_pile = [
37 urwid.Text( _('Snapshots') ),
38 urwid.Divider(),
39 ]
40 snapshots_pile.extend( self.build_snapshots_pile() )
41
42 display_widget = urwid.Columns( [
43 urwid.Pile( snapshots_pile ),
44 ( 'weight', 3, viewerwidget.ViewerWidget( main_win, config, self._snapshots ) )
45 ], 1 )
46 urwid.WidgetWrap.__init__( self, display_widget )
47
48 def build_snapshots_pile( self ):
49 snapshots_list = self._snapshots.get_snapshots_list()
50 groups = []
51 now = datetime.date.today()
52
53 #today
54 date = now
55 groups.append( ( _('Today'), self._snapshots.get_snapshot_id( date ), [] ) )
56 #yesterday
57 date = now - datetime.timedelta( days = 1 )
58 groups.append( ( _('Yesterday'), self._snapshots.get_snapshot_id( date ), [] ) )
59 #this week
60 date = now - datetime.timedelta( days = now.weekday() )
61 groups.append( ( _('This week'), self._snapshots.get_snapshot_id( date ), [] ) )
62 #last week
63 date = now - datetime.timedelta( days = now.weekday() + 7 )
64 groups.append( ( _('Last week'), self._snapshots.get_snapshot_id( date ), [] ) )
65 #any other groups
66 for snapshot_id in snapshots_list:
67 found = False
68 for group in groups:
69 if snapshot_id >= group[1]:
70 group[2].append( snapshot_id )
71 found = True
72 break
73
74 if not found:
75 year = int( snapshot_id[0:4] )
76 month = int( snapshot_id[4:6] )
77 date = datetime.date( year, month, 1 )
78
79 group_name = ''
80 if year == now.year:
81 group_name = date.strftime( '%B' ).capitalize()
82 else:
83 group_name = date.strftime( '%B, %Y' ).capitalize()
84
85 groups.append( ( group_name, self._snapshots.get_snapshot_id( date ), [ snapshot_id ] ) )
86
87 snapshots_buttons = []
88 pile_list = [
89 urwid.RadioButton( snapshots_buttons, _('Now'), self._main_win.is_selected_snapshot( '' ), self.change_snapshot, '' )
90 ]
91 for group in groups:
92 if len( group[2] ) > 0:
93 pile_list.append( urwid.Text( group[0] ) )
94 for snapshot_id in group[2]:
95 display_name = self._snapshots.get_snapshot_display_id( snapshot_id )
96 user_name = self._snapshots.get_snapshot_name( snapshot_id )
97 if len( user_name ) > 0:
98 display_name += ' - ' + user_name
99 pile_list.append( urwid.RadioButton( snapshots_buttons, display_name, self._main_win.is_selected_snapshot( snapshot_id ), self.change_snapshot, snapshot_id ) )
100
101 return pile_list
102
103 def change_snapshot( self, check_box, new_state, user_data ):
104 if new_state:
105 self._main_win.selected_snapshot = user_data
106 self._main_win.selected_snapshot_name = check_box.get_label()
107 self._main_win.update_content( RestoreWidget( self._main_win, self._config ), 5 )
0108
=== added file 'cli/snapshotname.py'
--- cli/snapshotname.py 1970-01-01 00:00:00 +0000
+++ cli/snapshotname.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,52 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18import urwid
19import gettext
20
21import logger
22import restorewidget
23import snapshots
24
25_=gettext.gettext
26
27class SnapshotName(urwid.WidgetWrap):
28
29 def __init__( self, main_win, config ):
30 self._main_win = main_win
31 self._config = config
32 self._snapshots = snapshots.Snapshots( config )
33
34 self._edit_box = urwid.Edit(( 'body', _('Snapshot Name') + ': ' ), self._snapshots.get_snapshot_name( main_win.selected_snapshot ) )
35 pile_list = [
36 urwid.AttrWrap( self._edit_box, 'edit_box', 'edit_focus' ),
37 urwid.Divider(),
38 urwid.GridFlow( [
39 urwid.AttrWrap( urwid.Button( _('OK'), self.ok_pressed ), 'button', 'button_focus' ),
40 urwid.AttrWrap( urwid.Button( _('Cancel'), self.cancel_pressed ), 'button', 'button_focus' )
41 ], 10, 2, 1, 'right' )
42 ]
43
44 display_widget = urwid.Pile( pile_list )
45 urwid.WidgetWrap.__init__( self, display_widget )
46
47 def ok_pressed( self, button ):
48 self._snapshots.set_snapshot_name( self._main_win.selected_snapshot, self._edit_box.get_edit_text().strip() )
49 self._main_win.update_content( restorewidget.RestoreWidget( self._main_win, self._config ), 5 )
50
51 def cancel_pressed( self, button ):
52 self._main_win.update_content( restorewidget.RestoreWidget( self._main_win, self._config ), 5 )
053
=== added file 'cli/snapshotswidget.py'
--- cli/snapshotswidget.py 1970-01-01 00:00:00 +0000
+++ cli/snapshotswidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,158 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
19import os.path
20import subprocess
21import tempfile
22import urwid
23import gettext
24
25import logger
26import restorewidget
27
28_=gettext.gettext
29
30class SnapshotsWidget(urwid.WidgetWrap):
31
32 def __init__( self, main_win, config, snapshots, path ):
33 self._main_win = main_win
34 self._config = config
35 self._snapshots = snapshots
36 self._path = path
37 self._selected_left = ''
38 self._selected_right = None
39
40 left_side, right_side = self._build_snapshot_lists()
41 pile_list = [
42 urwid.Text( _('Diff versions of') + ': %s' % path ),
43 urwid.Divider(),
44 urwid.Columns( [
45 urwid.Pile( left_side ),
46 urwid.Pile( right_side )
47 ], 1 ),
48 urwid.Divider(),
49 urwid.GridFlow( [
50 urwid.AttrWrap( urwid.Button( _('Jump to'), self.jump ), 'button', 'button_focus' ),
51 urwid.AttrWrap( urwid.Button( _('Diff'), self.diff ), 'button', 'button_focus' ),
52 urwid.AttrWrap( urwid.Button( _('Cancel'), self.go_back ), 'button', 'button_focus' )
53 ], 11, 2, 1, 'right' )
54 ]
55
56 display_widget = urwid.Pile( pile_list )
57 urwid.WidgetWrap.__init__( self, display_widget )
58
59 def _build_snapshot_lists( self ):
60 snapshots_list = self._snapshots.get_snapshots_list()
61 left_list = [
62 urwid.Text( _('Snapshots') + ':' ),
63 urwid.Divider()
64 ]
65 left_list_buttons = []
66 right_list = [
67 urwid.Text( _('Diff with') + ':' ),
68 urwid.Divider()
69 ]
70 right_list_buttons = []
71
72 path = self._snapshots.get_snapshot_path_to( self._main_win.selected_snapshot, self._path )
73 isdir = os.path.isdir( path )
74
75 # add now
76 path = self._path
77 if os.path.lexists( path ):
78 if os.path.isdir( path ) == isdir:
79 left_list.append( urwid.RadioButton( left_list_buttons, _('Now'), True, self.left_changed, '' ) )
80 right_list.append( urwid.RadioButton( right_list_buttons, _('Now'), False, self.right_changed, '' ) )
81
82 # add snapshots
83 for snapshot in snapshots_list:
84 path = self._snapshots.get_snapshot_path_to( snapshot, self._path )
85 if os.path.lexists( path ):
86 if os.path.isdir( path ) == isdir:
87 display_name = self._snapshots.get_snapshot_display_id( snapshot )
88 user_name = self._snapshots.get_snapshot_name( snapshot )
89 if len( user_name ) > 0:
90 display_name += ' - ' + user_name
91 if self._main_win.is_selected_snapshot( snapshot ):
92 selected = True
93 self._selected_right = snapshot
94 else:
95 selected = False
96 left_list.append( urwid.RadioButton( left_list_buttons, display_name, False, self.left_changed, snapshot ) )
97 right_list.append( urwid.RadioButton( right_list_buttons, display_name, selected, self.right_changed, snapshot ) )
98
99 return left_list, right_list
100
101 def left_changed( self, radio_button, new_state, user_data ):
102 if new_state:
103 self._selected_left = user_data
104
105 def right_changed( self, radio_button, new_state, user_data ):
106 if new_state:
107 self._selected_right = user_data
108
109 def jump( self, button ):
110 self._main_win.selected_snapshot = self._selected_left
111 self._main_win.update_content( restorewidget.RestoreWidget( self._main_win, self._config ), 5 )
112
113 def diff( self, button ):
114 if self._selected_right is not None:
115 self._main_win.update_content( DiffWidget( self._main_win, self._config, self._snapshots, self._path, self._selected_left, self._selected_right ), 5 )
116
117 def go_back( self, button ):
118 self._main_win.update_content( restorewidget.RestoreWidget( self._main_win, self._config ), 5 )
119
120class DiffWidget(SnapshotsWidget):
121 def __init__( self, main_win, config, snapshots, path, selected_left, selected_right ):
122 self._main_win = main_win
123 self._config = config
124
125 path_left = snapshots.get_snapshot_path_to( selected_left, path )
126 path_right = snapshots.get_snapshot_path_to( selected_right, path )
127
128 diff_cmd = 'diff "%s" "%s"' % ( path_left, path_right )
129 logger.info( 'diff cmd = "%s"' % diff_cmd )
130
131 wc_cmd = '%s | wc -l' % diff_cmd
132 callback = subprocess.Popen( wc_cmd, shell=True, stdout=subprocess.PIPE )
133 output = callback.communicate()
134 if main_win.main_loop.screen_size:
135 rows = main_win.main_loop.screen_size[1]
136 else:
137 rows = main_win.main_loop.screen.get_cols_rows()[1]
138
139 if int( output[0] ) > rows:
140 temp_file, temp_file_name = tempfile.mkstemp( '_bitdiff', os.path.basename( path ), text=True )
141 output_text = _('This diff was too long for the window, it has been written to') + ': %s' % temp_file_name
142 callback = subprocess.Popen( diff_cmd, shell=True, stdout=temp_file )
143 callback.communicate()
144 else:
145 callback = subprocess.Popen( diff_cmd, shell=True, stdout=subprocess.PIPE )
146 output = callback.communicate()
147 output_text = output[0]
148
149 pile_list = [
150 urwid.Text( diff_cmd ),
151 urwid.Divider(),
152 urwid.Text( output_text ),
153 urwid.Divider(),
154 urwid.AttrWrap( urwid.Button( _('OK'), self.go_back ), 'button', 'button_focus' )
155 ]
156
157 display_widget = urwid.Pile( pile_list )
158 urwid.WidgetWrap.__init__( self, display_widget )
0159
=== added file 'cli/viewerwidget.py'
--- cli/viewerwidget.py 1970-01-01 00:00:00 +0000
+++ cli/viewerwidget.py 2010-03-02 06:06:17 +0000
@@ -0,0 +1,132 @@
1# Back In Time
2# Copyright (C) 2010 Ryan Ahearn
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
19import os
20import os.path
21import urwid
22import gettext
23
24import logger
25import restorewidget
26import copywidget
27import snapshotswidget
28
29_=gettext.gettext
30
31class ViewerWidget(urwid.WidgetWrap):
32
33 def __init__( self, main_win, config, snapshots ):
34 self._main_win = main_win
35 self._config = config
36 self._snapshots = snapshots
37 self._selected = ''
38
39 if main_win.show_hidden:
40 hidden_label = _('Hide hidden files')
41 else:
42 hidden_label = _('Show hidden files')
43 self.build_fileview()
44 pile_list = [
45 urwid.Columns( [
46 ( 'fixed', 6, urwid.AttrWrap( urwid.Button( _('Up'), self.up_directory ), 'button', 'button_focus' ) ),
47 urwid.Text( main_win.current_directory, wrap='clip' )
48 ], 1),
49 urwid.Divider(),
50 urwid.Columns( [
51 ( 'fixed', 21, urwid.AttrWrap( urwid.Button( hidden_label, self.flip_hidden ), 'button', 'button_focus' ) ),
52 ( 'fixed', 11, urwid.AttrWrap( urwid.Button( _('Restore'), self.restore ), 'button', 'button_focus' ) ),
53 ( 'fixed', 8, urwid.AttrWrap( urwid.Button( _('Copy'), self.copy ), 'button', 'button_focus' ) ),
54 ( 'fixed', 13,urwid.AttrWrap( urwid.Button( _('Snapshots'), self.snapshots ), 'button', 'button_focus' ) )
55 ], 1 ),
56 urwid.Divider(),
57 urwid.Columns( [ self.build_shortcuts(),
58 ( 'weight', 3, urwid.Pile( self._file_list ) ) ], 1 )
59 ]
60 display_widget = urwid.Pile( pile_list )
61 urwid.WidgetWrap.__init__( self, display_widget )
62
63 def build_fileview( self ):
64 self._file_list = [
65 urwid.Text( _('Files and Folders') ),
66 urwid.Divider()
67 ]
68
69 sid = self._main_win.selected_snapshot
70
71 full_path = self._snapshots.get_snapshot_path_to( sid, self._main_win.current_directory )
72
73 if not self._snapshots.can_open_path( sid, full_path ):
74 self._file_list.append( urwid.Text( _('This folder does not exist') ) )
75 self._file_list.append( urwid.Text( _('in current snapshot !' ) ) )
76 return
77
78 directory = os.listdir( full_path )
79 decorated = [ ( not os.path.isdir( os.path.join( full_path, file_name ) ), file_name ) for file_name in directory ]
80 decorated.sort()
81 restore_radios = []
82 for is_file, file_name in decorated:
83 if self._main_win.show_hidden or not file_name.startswith( '.' ):
84 if is_file:
85 self._file_list.append( urwid.RadioButton( restore_radios, file_name, False, self.select_for_restore, file_name ) )
86 else:
87 self._file_list.append( urwid.Columns( [
88 ( 'fixed', 4, urwid.RadioButton( restore_radios, '', False, self.select_for_restore, file_name ) ),
89 urwid.AttrWrap( urwid.Button( file_name, self.go_to_directory ), 'button', 'button_focus' )
90 ], 0 ) )
91
92
93 def select_for_restore( self, radio_button, new_state, user_data ):
94 if new_state:
95 self._selected = os.path.join( self._main_win.current_directory, user_data )
96
97 def go_to_directory( self, button ):
98 new_directory = os.path.join( self._main_win.current_directory, button.get_label() )
99 self._main_win.update_current_directory( new_directory )
100
101 def build_shortcuts( self ):
102 pile_list = [ urwid.Text( _('Shortcuts') ) ]
103
104 included_folders = self._config.get_include_folders()
105 for label in included_folders:
106 pile_list.append( urwid.AttrWrap( urwid.Button( label, self.go_to_shortcut ), 'button', 'button_focus' ) )
107
108 return urwid.Pile( pile_list )
109
110 def go_to_shortcut( self, button ):
111 self._main_win.update_current_directory( button.get_label() )
112
113 def up_directory( self, button ):
114 self._main_win.update_current_directory( os.path.dirname( self._main_win.current_directory ) )
115
116 def flip_hidden( self, button ):
117 self._main_win.show_hidden = not self._main_win.show_hidden
118 self._main_win.update_content( restorewidget.RestoreWidget( self._main_win, self._config ), 5 )
119
120 def restore( self, button ):
121 if self._main_win.selected_snapshot != '' and self._selected != '':
122 self._snapshots.restore( self._main_win.selected_snapshot, self._selected )
123
124 def copy( self, button ):
125 if self._main_win.selected_snapshot != '' and self._selected != '':
126 source_path = self._snapshots.get_snapshot_path_to( self._main_win.selected_snapshot, self._selected )
127 self._main_win.update_content( copywidget.CopyWidget( self._main_win, self._config, source_path ), 5 )
128
129 def snapshots( self, button ):
130 if self._selected != '':
131 self._main_win.update_content( snapshotswidget.SnapshotsWidget( self._main_win, self._config, self._snapshots, self._selected ), 5 )
132
0133
=== modified file 'common/backintime.py'
--- common/backintime.py 2009-12-17 10:18:53 +0000
+++ common/backintime.py 2010-03-02 06:06:18 +0000
@@ -83,7 +83,6 @@
8383
84def start_app( app_name = 'backintime', extra_args = [] ):84def start_app( app_name = 'backintime', extra_args = [] ):
85 cfg = config.Config()85 cfg = config.Config()
86 print_version( cfg, app_name )
8786
88 skip = False87 skip = False
89 index = 088 index = 0
@@ -111,6 +110,7 @@
111 sys.exit(0)110 sys.exit(0)
112111
113 if arg == '--version' or arg == '-v':112 if arg == '--version' or arg == '-v':
113 print_version( cfg, app_name )
114 sys.exit(0)114 sys.exit(0)
115115
116 if arg == '--license':116 if arg == '--license':
117117
=== modified file 'common/logger.py'
--- common/logger.py 2009-11-02 13:52:00 +0000
+++ common/logger.py 2010-03-02 06:06:18 +0000
@@ -27,14 +27,11 @@
27 syslog.closelog()27 syslog.closelog()
2828
29def error( msg ):29def error( msg ):
30 print 'ERROR: ' + msg
31 syslog.syslog( syslog.LOG_ERR, 'ERROR: ' + msg )30 syslog.syslog( syslog.LOG_ERR, 'ERROR: ' + msg )
3231
33def warning( msg ):32def warning( msg ):
34 print 'WARNING: ' + msg
35 syslog.syslog( syslog.LOG_WARNING, 'WARNING: ' + msg )33 syslog.syslog( syslog.LOG_WARNING, 'WARNING: ' + msg )
3634
37def info( msg ):35def info( msg ):
38 print 'INFO: ' + msg
39 syslog.syslog( syslog.LOG_INFO, 'INFO: ' + msg )36 syslog.syslog( syslog.LOG_INFO, 'INFO: ' + msg )
4037
4138
=== modified file 'makedeb.sh'
--- makedeb.sh 2009-05-12 10:13:25 +0000
+++ makedeb.sh 2010-03-02 06:06:17 +0000
@@ -1,6 +1,6 @@
1#!/bin/bash1#!/bin/bash
22
3for i in common gnome kde4; do3for i in common gnome kde4 cli; do
4 PKGNAME=`cat $i/debian_specific/control | grep "Package:" | cut -d" " -f2`4 PKGNAME=`cat $i/debian_specific/control | grep "Package:" | cut -d" " -f2`
5 PKGVER=`cat $i/debian_specific/control | grep "Version:" | cut -d" " -f2`5 PKGVER=`cat $i/debian_specific/control | grep "Version:" | cut -d" " -f2`
6 PKGARCH=`cat $i/debian_specific/control | grep "Architecture:" | cut -d" " -f2`6 PKGARCH=`cat $i/debian_specific/control | grep "Architecture:" | cut -d" " -f2`
77
=== modified file 'updateversion.sh'
--- updateversion.sh 2009-04-27 13:43:00 +0000
+++ updateversion.sh 2010-03-02 06:06:17 +0000
@@ -12,6 +12,9 @@
12echo "Update 'kde4/debian_specific/control'"12echo "Update 'kde4/debian_specific/control'"
13sed -i -e "s/^Version: .*$/Version: $VERSION/" -e "s/backintime-common (= [^)]*)/backintime-common (= $VERSION)/" kde4/debian_specific/control13sed -i -e "s/^Version: .*$/Version: $VERSION/" -e "s/backintime-common (= [^)]*)/backintime-common (= $VERSION)/" kde4/debian_specific/control
1414
15echo "Update 'cli/debian_specific/control'"
16sed -i -e "s/^Version: .*$/Version: $VERSION/" -e "s/backintime-common (= [^)]*)/backintime-common (= $VERSION)/" cli/debian_specific/control
17
15echo "Update 'common/config.py'"18echo "Update 'common/config.py'"
16sed -i -e "s/^\tVERSION = '.*'$/\tVERSION = '$VERSION'/" common/config.py19sed -i -e "s/^\tVERSION = '.*'$/\tVERSION = '$VERSION'/" common/config.py
1720
@@ -33,6 +36,16 @@
33sed -i -e "s/\.TH\(.*\)\"version\([^\"]*\)\"\(.*\)$/.TH\1\"version $VERSION\"\3/" $FILE36sed -i -e "s/\.TH\(.*\)\"version\([^\"]*\)\"\(.*\)$/.TH\1\"version $VERSION\"\3/" $FILE
34gzip --best $FILE37gzip --best $FILE
3538
39echo "Update CLI man page"
40FILE=cli/man/C/backintime-config.1
41gzip -d $FILE.gz
42sed -i -e "s/\.TH\(.*\)\"version\([^\"]*\)\"\(.*\)$/.TH\1\"version $VERSION\"\3/" $FILE
43gzip --best $FILE
44FILE=cli/man/C/backintime-restore.1
45gzip -d $FILE.gz
46sed -i -e "s/\.TH\(.*\)\"version\([^\"]*\)\"\(.*\)$/.TH\1\"version $VERSION\"\3/" $FILE
47gzip --best $FILE
48
36echo "Update help .omf file"49echo "Update help .omf file"
37sed -i -e "s/^\([ \]*\)<version\([^0-9]*\)\([^\"]*\)\(.*\)$/\1<version\2$VERSION\4/" gnome/docbook/C/backintime-C.omf50sed -i -e "s/^\([ \]*\)<version\([^0-9]*\)\([^\"]*\)\(.*\)$/\1<version\2$VERSION\4/" gnome/docbook/C/backintime-C.omf
3851

Subscribers

People subscribed via source and target branches