1 import tempfile
, sys
, shutil
, os
, subprocess
, gobject
, tarfile
, optparse
3 INSTALLER_MODE
= @INSTALLER_MODE@
5 def get_busy_pointer():
6 # See http://mail.gnome.org/archives/gtk-list/2007-May/msg00100.html
8 \x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\
9 \x0c\x00\x00\x00\x1c\x00\x00\x00\x3c\x00\x00\x00\
10 \x7c\x00\x00\x00\xfc\x00\x00\x00\xfc\x01\x00\x00\
11 \xfc\x3b\x00\x00\x7c\x38\x00\x00\x6c\x54\x00\x00\
12 \xc4\xdc\x00\x00\xc0\x44\x00\x00\x80\x39\x00\x00\
13 \x80\x39\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
14 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
15 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
16 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
17 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
18 \x00\x00\x00\x00\x00\x00\x00\x00"
21 pix
= gtk
.gdk
.bitmap_create_from_data(None, bit_data
, 32, 32)
22 color
= gtk
.gdk
.Color()
23 return gtk
.gdk
.Cursor(pix
, pix
, color
, color
, 2, 2)
25 #old bug http://bugzilla.gnome.org/show_bug.cgi?id=103616
26 return gtk
.gdk
.Cursor(gtk
.gdk
.WATCH
)
30 w
= gtk
.Dialog(title
= "Zero Install")
32 w
.set_resizable(False)
33 w
.set_has_separator(False)
34 w
.vbox
.set_border_width(4)
35 hbox
= gtk
.HBox(False, 12)
36 hbox
.set_border_width(5)
37 image
= gtk
.image_new_from_stock(gtk
.STOCK_DIALOG_INFO
, gtk
.ICON_SIZE_DIALOG
)
38 image
.set_alignment(0.5, 0.5)
40 message_vbox
= gtk
.VBox(False, 12)
41 message_vbox
.pack_start(gtk
.Label('The software is being unpacked. Please wait...'), True, True)
42 message_vbox
.set_border_width(12)
44 progress_bar
= gtk
.ProgressBar()
45 message_vbox
.add(progress_bar
)
47 actions_vbox
= gtk
.VBox(False, 4)
48 label
= gtk
.Label('Actions:')
49 label
.set_alignment(0, 0.5)
50 actions_vbox
.pack_start(label
, False, True, 0)
52 if subprocess
.call('which xdg-desktop-menu',
53 shell
=True, stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
):
54 self
.add_to_menu_option
= gtk
.CheckButton('(no xdg-desktop-menu command;\n'
55 'to add menu items, install xdg-utils first)')
56 actions_vbox
.pack_start(self
.add_to_menu_option
, False, True, 0)
57 self
.add_to_menu_option
.set_active(False)
58 self
.add_to_menu_option
.set_sensitive(False)
60 self
.add_to_menu_option
= gtk
.CheckButton('Add to menu')
61 actions_vbox
.pack_start(self
.add_to_menu_option
, False, True, 0)
62 self
.add_to_menu_option
.set_active(True)
64 self
.run_option
= gtk
.CheckButton('Run program')
65 self
.run_option
.set_active(True)
66 actions_vbox
.pack_start(self
.run_option
, False, True, 0)
68 def update_sensitive(option
):
69 w
.set_response_sensitive(gtk
.RESPONSE_OK
,
70 self
.add_to_menu_option
.get_active() or self
.run_option
.get_active())
71 self
.add_to_menu_option
.connect('toggled', update_sensitive
)
72 self
.run_option
.connect('toggled', update_sensitive
)
74 self
.notebook
= gtk
.Notebook()
75 self
.notebook
.set_show_tabs(False)
76 self
.notebook
.set_show_border(False)
77 self
.notebook
.append_page(message_vbox
, None)
78 self
.notebook
.append_page(actions_vbox
, None)
80 hbox
.pack_start(image
, False, False, 0)
81 hbox
.pack_start(self
.notebook
, True, True)
82 w
.vbox
.pack_start(hbox
, False, False, 0)
83 cancel_button
= w
.add_button(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
)
84 cancel_button
.unset_flags(gtk
.CAN_DEFAULT
)
85 self
.ok_button
= w
.add_button(gtk
.STOCK_OK
, gtk
.RESPONSE_OK
)
86 w
.set_response_sensitive(gtk
.RESPONSE_OK
, False)
87 w
.set_position(gtk
.WIN_POS_MOUSE
)
88 w
.set_title('Zero Install')
89 w
.set_default_size(400, 300)
91 w
.window
.set_cursor(get_busy_pointer())
94 def response(w
, resp
):
95 print >>sys
.stderr
, "Cancelled at user's request"
99 self
.response_handler
= w
.connect('response', response
)
102 def finish_install(self
):
104 self
.notebook
.next_page()
105 self
.w
.disconnect(self
.response_handler
)
106 self
.w
.window
.set_cursor(None)
107 self
.w
.set_response_sensitive(gtk
.RESPONSE_OK
, True)
108 self
.ok_button
.grab_focus()
114 if resp
!= gtk
.RESPONSE_OK
:
115 raise Exception("Cancelled at user's request")
117 if self
.add_to_menu_option
.get_active():
118 install
.add_to_menu([selections
.interface
for selections
in selections_list
])
121 tmp
= tempfile
.mkdtemp(prefix
= '0export-')
126 print "Extracting bootstrap data..."
128 setup_path
= sys
.argv
[1]
129 archive_offset
= int(sys
.argv
[2])
132 parser
= optparse
.OptionParser(usage
="usage: %s\n"
133 "Run self-extracting installer" % setup_path
)
135 parser
.add_option("-v", "--verbose", help="more verbose output", action
='count')
136 parser
.add_option("-x", "--extract-only", help="stop after extracting", action
='count')
138 (options
, args
) = parser
.parse_args()
142 logger
= logging
.getLogger()
143 if options
.verbose
== 1:
144 logger
.setLevel(logging
.INFO
)
146 logger
.setLevel(logging
.DEBUG
)
148 extract_only
= options
.extract_only
150 if len(args
) == 0 and 'DISPLAY' in os
.environ
:
151 import pygtk
; pygtk
.require('2.0')
153 if gtk
.gdk
.get_display() is None:
154 print >>sys
.stderr
, "Failed to open display; using console mode"
161 self_stream
= file(setup_path
, 'rb')
162 self_stream
.seek(archive_offset
)
163 old_umask
= os
.umask(077)
164 mainloop
= gobject
.MainLoop(gobject
.main_context_default())
165 archive
= tarfile
.open(name
=self_stream
.name
, mode
='r|',
168 # Extract the bootstrap data (interfaces, 0install itself)
169 bootstrap_stream
= None
170 for tarmember
in archive
:
171 if tarmember
.name
== 'bootstrap.tar.bz2':
172 bootstrap_stream
= archive
.extractfile(tarmember
)
175 raise Exception("No bootstrap data in archive (broken?)")
177 bootstrap_tar
= tarfile
.open(name
=bootstrap_stream
.name
, mode
='r|bz2',
178 fileobj
=bootstrap_stream
)
182 for tarinfo
in bootstrap_tar
:
183 tarinfo
.mode
= (tarinfo
.mode |
0644) & ~umask
184 bootstrap_tar
.extract(tarinfo
, tmp
)
186 items
.append(tarinfo
)
187 for tarinfo
in items
:
188 path
= os
.path
.join(tmp
, tarinfo
.name
)
189 os
.utime(path
, (tarinfo
.mtime
, tarinfo
.mtime
))
190 bootstrap_tar
.close()
191 bootstrap_stream
.close()
194 # Stop Python adding .pyc files
195 for root
, dirs
, files
in os
.walk(os
.path
.join(tmp
, 'zeroinstall')):
199 sys
.path
.insert(0, tmp
)
200 sys
.argv
[0] = os
.path
.join(tmp
, 'install.py')
202 print "Installing..."
204 installer
= install
.Installer()
205 selections_list
= installer
.do_install(self_stream
, progress_bar
, archive_offset
)
211 # Just process the first one (is this right?)
212 selections
= selections_list
[0]
214 # Download any missing selections
215 if selections
.get_unavailable_selections(install
.config
, include_packages
= True):
216 print "Downloading..."
217 blocker
= selections
.download_missing(install
.config
, include_packages
= True)
218 tasks
.wait_for_blocker(blocker
)
219 print "Downloading done"
221 if w
and not w
.run_option
.get_active():
223 assert not args
, "Download only mode, but arguments given: %s" % args
226 # Do a dry-run before deleting the temporary directory, to ensure all the 0install
227 # code is already loaded.
228 from zeroinstall
.injector
import run
229 from StringIO
import StringIO
230 old_stdout
= sys
.stdout
231 sys
.stdout
= StringIO()
232 run
.execute_selections(selections
, args
, dry_run
= True, stores
= install
.config
.stores
)
233 sys
.stdout
= old_stdout
236 print("Extracted files are in %s" % tmp
)
239 print "Removing temporary files..."
240 for root
, dirs
, files
in os
.walk(os
.path
.join(tmp
, 'zeroinstall')):
245 run
.execute_selections(selections
, args
, stores
= install
.config
.stores
)