/stdhome

To get this branch, use:
bzr branch http://bzr.ed.am/stdhome

« back to all changes in this revision

Viewing changes to lib/stdhome/program.py

  • Committer: Tim Marston
  • Date: 2014-02-12 21:51:08 UTC
  • Revision ID: tim@ed.am-20140212215108-stk5z0nlvgpi4oa8
added bzr as a vcs backend; finished init command; implemented deployment

Show diffs side-by-side

added added

removed removed

1
 
# stdhome.py
 
1
# program.py
2
2
#
3
3
# Copyright (C) 2013 Tim Marston <tim@edm.am>
4
4
#
19
19
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
20
 
21
21
 
22
 
import sys, os
23
 
import getopt
24
 
 
25
 
 
26
 
class Stdhome:
 
22
import os, sys, getopt
 
23
import the
 
24
 
 
25
 
 
26
class Program:
27
27
 
28
28
 
29
29
        def __init__( self, version ):
 
30
                self.name = os.path.basename( sys.argv[ 0 ] )
30
31
                self.version = version
31
 
                self.program = os.path.basename( sys.argv[ 0 ] )
 
32
 
 
33
 
 
34
        def die( self, error_message ):
 
35
                prefix = self.name + ( ' ' + the.command if the.command else '' )
 
36
                print >> sys.stderr, '%s: %s' % ( prefix, error_message )
 
37
                exit( 1 )
32
38
 
33
39
 
34
40
        def print_usage( self, error_message ):
35
 
                print >> sys.stderr, self.program + ": " + error_message
36
 
                print >> sys.stderr, "Try '" + self.program + " --help' for more information."
37
 
                exit( 1 )
 
41
                command = ' ' + the.command if the.command else ''
 
42
                self.die( error_message + \
 
43
                                  "\nTry '%s%s --help' for more information." % \
 
44
                                  ( self.name, command ) )
38
45
 
39
46
 
40
47
        def print_help( self ):
41
 
                print "Usage: " + self.program + " COMMAND [OPTION]..."
 
48
                print "Usage: " + self.name + " COMMAND [OPTION]..."
42
49
                print
43
50
                #      01234567890123456789012345678901234567890123456789012345678901234567890123456789
44
 
                print "Manage your home directories, across multiple computers, similar to how you"
45
 
                print "would software under version control."
 
51
                print "Tool to manage a set of files in your home directory and distribute them across"
 
52
                print "multiple computers, merging local changes (in the same way as you would manage"
 
53
                print "source code under version control)."
46
54
                print
47
55
                print "Global options (for all commands):"
48
56
                print "     --help     display help and exit"
54
62
                print "  resolve       try to finish an update (that had conflicts)"
55
63
                print "  add           add local files/changes to the repository"
56
64
                print "  remove        remove a local file from the repository"
 
65
                print "  status        list files that have changed locally"
 
66
                print "  diff          shows changes made to local files"
57
67
                print "  revert        undo changes made to a local file"
58
68
                print "  stage-add     stage local files/changes"
59
69
                print "  stage-remove  stage the removal of files"
60
70
                print "  stage-revert  revert staged changes"
61
71
                print "  stage-status  show status of staging area"
 
72
                print "  stage-diff    shows staged changes"
62
73
                print "  stage-commit  commit staged changes to repository"
63
74
                print
64
75
                print "For help about a particular command (including the additional options that the"
65
76
                print "command accepts) try typing:"
66
 
                print "  $ " + self.program + " COMMAND --help"
 
77
                print "  $ " + self.name + " COMMAND --help"
67
78
                exit( 0 )
68
79
 
69
80
 
92
103
                - `command`: the given command
93
104
                """
94
105
                # commands
95
 
                if [ 'init', 'update', 'resolve', 'add', 'remove', 'revert',
96
 
                         'stage-add', 'stage-remove', 'stage-revert', 'stage-status',
97
 
                         'stage-commit' ].count( command ) == 1:
 
106
                if [ 'init', 'update', 'resolve', 'add', 'remove', 'revert', 'status',
 
107
                         'diff', 'stage-add', 'stage-remove', 'stage-revert',
 
108
                         'stage-status', 'stage-diff', 'stage-commit'
 
109
                ].count( command ) == 1:
98
110
                        return command
99
111
 
100
 
                # aliases
 
112
                # resolve aliases
101
113
                elif command == 'up':
102
114
                        return 'update'
103
115
                elif command == 'rm':
123
135
                        args = args[ 1 : ]
124
136
                return None
125
137
 
 
138
 
126
139
        def run( self ):
127
140
                # make an initial attempt to parse the command line, looking only for
128
141
                # --help and --version, so that they have the chance to run without a
132
145
                                sys.argv[ 1: ], "",
133
146
                                [ "help", "version" ] )
134
147
 
135
 
                        for opt, optargs in opts:
 
148
                        for opt, optarg in opts:
136
149
                                # we only show help if there are no non-option arguments (e.g.,
137
150
                                # a command) specified.  If a command has been specified it will
138
151
                                # have to be parsed and --help will be handled by it, instead)
142
155
                                        self.print_version()
143
156
 
144
157
                except getopt.GetoptError as e:
145
 
                        # ignore any errors -- we aren't parsing the command line properly
 
158
                        # ignore errors -- we aren't parsing the command line properly yet
146
159
                        pass
147
160
 
148
161
                # find the first non-option argument (the command)
149
 
                self.command = self.get_command_argument( sys.argv[ 1: ] )
150
 
                if self.command == None:
 
162
                the.command = self.get_command_argument( sys.argv[ 1: ] )
 
163
                if the.command == None:
151
164
                        self.print_usage( "missing command" )
152
165
 
153
166
                # check command is valid
154
 
                self.command = self.check_command( self.command )
155
 
                if self.command == None:
 
167
                the.command = self.check_command( the.command )
 
168
                if the.command == None:
156
169
                        self.print_usage( "bad command" )
157
170
 
158
 
                # calculate class name
159
 
                bits = self.command.split( '-' )
 
171
                # calculate module and class name
 
172
                bits = the.command.split( '-' )
160
173
                class_name = 'Command'
 
174
                module_name = 'command'
161
175
                for bit in bits:
162
176
                        class_name += bit[ 0 ].upper() + bit[ 1 : ]
163
 
 
164
 
                # instantiate and run the command class
165
 
                module = __import__( 'stdhome.command_' + self.command )
166
 
                the_class = getattr( module, class_name )
167
 
                instance = the_class()
168
 
                instance.run( self )
 
177
                        module_name += '_' + bit
 
178
 
 
179
                # import module and instantiate the class
 
180
                module = __import__( 'stdhome.' + module_name,
 
181
                                                         fromlist = [ class_name ] )
 
182
                instance = getattr( module, class_name )()
 
183
 
 
184
                # run the command
 
185
                try:
 
186
                        instance.parse_command_line()
 
187
                        instance.run()
 
188
                except ( getopt.GetoptError, self.UsageError ) as e:
 
189
                        self.print_usage( e.msg )
 
190
                except self.FatalError as e:
 
191
                        message = e.msg.rstrip()
 
192
                        if the.verbose and hasattr( e, 'output' ) and e.output:
 
193
                                message += '\n\nOUTPUT:\n' + e.output.rstrip()
 
194
                        self.die( message )
 
195
 
 
196
 
 
197
        class UsageError( Exception ):
 
198
 
 
199
                def __init__( self, error_message ):
 
200
                        self.msg = error_message
 
201
 
 
202
 
 
203
        class FatalError( Exception ):
 
204
 
 
205
                def __init__( self, message, output = None ):
 
206
                        self.msg = message
 
207
                        self.output = output