Mercurial > gcp
comparison gcp @ 0:674ce820a4ef
initial commit
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 25 Aug 2010 16:11:34 +0800 |
parents | |
children | 995487813501 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:674ce820a4ef |
---|---|
1 #!/usr/bin/python | |
2 # -*- coding: utf-8 -*- | |
3 | |
4 """ | |
5 gcp: Goffi's CoPier | |
6 Copyright (C) 2010 Jérôme Poisson (goffi@goffi.org) | |
7 | |
8 This program is free software: you can redistribute it and/or modify | |
9 it under the terms of the GNU General Public License as published by | |
10 the Free Software Foundation, either version 3 of the License, or | |
11 (at your option) any later version. | |
12 | |
13 This program is distributed in the hope that it will be useful, | |
14 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 GNU General Public License for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 """ | |
21 | |
22 ### logging ### | |
23 import logging | |
24 from logging import debug, info, error, warning | |
25 logging.basicConfig(level=logging.DEBUG, | |
26 format='%(message)s') | |
27 ### | |
28 import sys | |
29 import os,os.path | |
30 from optparse import OptionParser #To be replaced by argparse ASAP | |
31 try: | |
32 import gobject | |
33 #DBus | |
34 import dbus, dbus.glib | |
35 import dbus.service | |
36 import dbus.mainloop.glib | |
37 except ImportError,e: | |
38 error("Error during import") | |
39 error("Please check dependecies:",e) | |
40 exit(2) | |
41 try: | |
42 from progressbar import ProgressBar, Percentage, Bar, ETA, FileTransferSpeed | |
43 pbar_available=True | |
44 except ImportError, e: | |
45 info ('ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar') | |
46 info ('Progress bar deactivated\n--\n') | |
47 pbar_available=False | |
48 | |
49 NAME = "gcp (Goffi's copier)" | |
50 NAME_SHORT = "gcp" | |
51 VERSION = '0.1' | |
52 | |
53 ABOUT = NAME+" v"+VERSION+""" (c) Jérôme Poisson (aka Goffi) 2010 | |
54 | |
55 --- | |
56 """+NAME+""" Copyright (C) 2010 Jérôme Poisson | |
57 This program comes with ABSOLUTELY NO WARRANTY; | |
58 This is free software, and you are welcome to redistribute it | |
59 under certain conditions. | |
60 --- | |
61 | |
62 This software is an advanced file copier | |
63 Get the latest version at http://www.goffi.org | |
64 """ | |
65 | |
66 const_DBUS_INTERFACE = "org.goffi.gcp" | |
67 const_DBUS_PATH = "/org/goffi/gcp" | |
68 | |
69 | |
70 class DbusObject(dbus.service.Object): | |
71 | |
72 def __init__(self, gcp, bus, path): | |
73 self._gcp = gcp | |
74 dbus.service.Object.__init__(self, bus, path) | |
75 debug("Init DbusObject...") | |
76 self.cb={} | |
77 | |
78 @dbus.service.method(const_DBUS_INTERFACE, | |
79 in_signature='', out_signature='s') | |
80 def getVersion(self): | |
81 """Get gcp version | |
82 @return: version as string""" | |
83 return VERSION | |
84 | |
85 @dbus.service.method(const_DBUS_INTERFACE, | |
86 in_signature='sas', out_signature='b') | |
87 def addArgs(self, source_path, args): | |
88 """Add arguments to gcp as if there were entered on its own command line | |
89 @source_path: current working dir to use as base for arguments, as given by os.getcwd() | |
90 @args: list of strings - without command name -, as given by sys.argv[1:]""" | |
91 return self._gcp.parseArguments(args, source_path) | |
92 | |
93 class GCP(): | |
94 | |
95 def __init__(self): | |
96 try: | |
97 sessions_bus = dbus.SessionBus() | |
98 db_object = sessions_bus.get_object(const_DBUS_INTERFACE, | |
99 const_DBUS_PATH) | |
100 self.gcp_main = dbus.Interface(db_object, | |
101 dbus_interface=const_DBUS_INTERFACE) | |
102 self._main_instance = False | |
103 | |
104 except dbus.exceptions.DBusException,e: | |
105 if e._dbus_error_name=='org.freedesktop.DBus.Error.ServiceUnknown': | |
106 self.launchDbusMainInstance() | |
107 debug ("gcp launched") | |
108 self._main_instance = True | |
109 else: | |
110 raise e | |
111 | |
112 def launchDbusMainInstance(self): | |
113 debug ("Init DBus...") | |
114 session_bus = dbus.SessionBus() | |
115 self.dbus_name = dbus.service.BusName(const_DBUS_INTERFACE, session_bus) | |
116 self.dbus_object = DbusObject(self, session_bus, const_DBUS_PATH) | |
117 | |
118 self.copy_list = [] | |
119 self.mounts = self.__getMountPoints() | |
120 | |
121 def getFsType(self, path): | |
122 fs='' | |
123 for mount in self.mounts: | |
124 if path.startswith(mount) and len(self.mounts[mount])>len(fs): | |
125 fs = self.mounts[mount] | |
126 return fs | |
127 | |
128 def __getMountPoints(self): | |
129 """Parse /proc/mounts to get currently mounted devices""" | |
130 #TODO: reparse when a new device is added/a device is removed | |
131 ret = {} | |
132 try: | |
133 with open("/proc/mounts",'r') as mounts: | |
134 for line in mounts.readlines(): | |
135 fs_spec, fs_file, fs_vfstype, fs_mntops, fs_freq, fs_passno = line.split(' ') | |
136 ret[fs_file] = fs_vfstype | |
137 except: | |
138 error ("Can't read mounts table") | |
139 return ret | |
140 | |
141 def __appendToList(self, path, options): | |
142 """Add a file to the copy list | |
143 @param path: absolute path of file | |
144 @param options: options as return by optparse""" | |
145 debug ("Adding to copy list: %s (%s)", path, self.getFsType(path)) | |
146 self.copy_list.append((path, options)) | |
147 | |
148 def __appendDirToList(self, dirpath, options): | |
149 """Add recursively directory to the copy list | |
150 @param path: absolute path of dir | |
151 @param options: options as return by optparse""" | |
152 try: | |
153 for filename in os.listdir(dirpath): | |
154 filepath = os.path.join(dirpath,filename) | |
155 if os.path.isdir(filepath): | |
156 self.__appendDirToList(filepath, options) | |
157 else: | |
158 self.__appendToList(filepath,options) | |
159 except OSError,e: | |
160 error("Can't copy %(path)s: %(exception)s" % {'path':dirpath, 'exception':e.strerror}) | |
161 | |
162 def __checkArgs(self, options, source_path, args): | |
163 """Check thats args are files, and add them to copy list""" | |
164 for path in args: | |
165 abspath = os.path.normpath(os.path.join(source_path, path)) | |
166 if not os.path.exists(abspath): | |
167 warning("The path given in arg doesn't exist or is not accessible: %s",abspath) | |
168 else: | |
169 if os.path.isdir(abspath): | |
170 if not options.recursive: | |
171 warning ('omitting directory "%s"' % abspath) | |
172 else: | |
173 self.__appendDirToList(abspath, options) | |
174 else: | |
175 self.__appendToList(abspath,options) | |
176 | |
177 | |
178 def parseArguments(self, full_args=sys.argv[1:], source_path = os.getcwd()): | |
179 _usage=""" | |
180 %prog [options] FILE1 [FILE2 ...] DEST | |
181 | |
182 %prog --help for options list | |
183 """ | |
184 parser = OptionParser(usage=_usage,version=ABOUT) | |
185 | |
186 parser.add_option("-r", "--recursive", action="store_true", default=False, | |
187 help="copy directories recursively") | |
188 | |
189 (options, args) = parser.parse_args(full_args) | |
190 | |
191 if not self._main_instance: | |
192 if args: | |
193 info ("There is already one instance of %s running, pluging to it" % NAME_SHORT) | |
194 self.gcp_main.addArgs(os.getcwd(),full_args) | |
195 else: | |
196 error ("There is already one instance of %s running, but we have no argument to send" % NAME_SHORT) | |
197 sys.exit(1) | |
198 else: | |
199 debug("adding args to gcp: %s",args) | |
200 self.__checkArgs(options, source_path, args) | |
201 | |
202 def go(self): | |
203 self.loop = gobject.MainLoop() | |
204 try: | |
205 self.loop.run() | |
206 except KeyboardInterrupt: | |
207 info("User interruption: good bye") | |
208 | |
209 | |
210 if __name__ == "__main__": | |
211 gcp = GCP() | |
212 gcp.parseArguments() | |
213 if gcp._main_instance: | |
214 gcp.go() | |
215 |