File: build.py

package info (click to toggle)
live-magic 1.5%2Blenny2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 544 kB
  • ctags: 279
  • sloc: python: 1,589; sh: 85; makefile: 9
file content (174 lines) | stat: -rw-r--r-- 6,106 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# -*- coding: utf-8 -*-
#
#   live-magic - GUI frontend to create Debian LiveCDs, etc.
#   Copyright (C) 2007-2008 Chris Lamb <chris@chris-lamb.co.uk>
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import pwd
import sys
import gobject
import subprocess

BUILDING, CANCELLED, CANCELLED_CLEAN, FAILED, \
    FAILED_CLEAN, OK, OK_CLEAN, DONE = range(8)

from LiveMagic.utils import find_resource

LOG_FILE = 'build-log.txt'
STATUS_FILE = '.status'

class BuildController(object):

    def do_show_build_window(self, build_close_callback):
        self.state = BUILDING
        self.build_successful = False

        self.uid, self.gid = [int(x) for x in self.options.build_for.split(':', 2)]

        f = open(os.path.join(LOG_FILE), 'w')
        print >>f, "I: live-magic respawned as root"
        f.close()

        # Set initial titles and state
        self.view.set_build_status_change(initial=True)

        # Show window
        self.view.do_show_window_build(build_close_callback)

        # Start pulsing
        gobject.timeout_add(80, self.do_pulse_cb)

        # Fork command
        cmd = [find_resource('live-magic-builder')]
        self.pid = self.view.vte_terminal.fork_command(cmd[0], cmd, None, os.getcwd())

        if self.pid < 0:
            self.view.set_build_titles(_("Error creating Debian Live system!"), \
                "Could not fork the build process!")
            self.view.set_build_status_change(initial=False)

    def on_window_build_delete_event(self, *args):
        # If no command is running, close the window
        if self.pid < 0:
            self.view.do_hide_window_build()
        return True

    def on_vte_child_exited(self, *args):
        def _exec(*cmds):
            glue = ' | tee -a %s ;' % LOG_FILE
            args = ['/bin/sh', '-c', glue.join(cmds)]
            self.view.vte_terminal.fork_command(args[0], args, None, os.getcwd())

        def set_cleaning_status():
            try:
                os.remove(STATUS_FILE)
            except:
                # This may fail as we removed the build directory
                pass
            self.view.set_build_uncancellable()
            self.view.set_build_titles(_("Cleaning build system"),
                _("Purging unnecessary parts of the build system..."))

        def ok():
            self.view.set_build_titles(_("Build process finished"),
                _("Your Debian Live system has been created successfully."))

            if self.options.kde_full_session != '-':
                os.environ['KDE_FULL_SESSION'] = self.options.kde_full_session
            if self.options.gnome_desktop_session_id != '-':
                os.environ['GNOME_DESKTOP_SESSION_ID'] = self.options.gnome_desktop_session_id

            # Try some file managers.
            for manager in ('/usr/bin/xdg-open', '/usr/bin/pcmanfm', '/usr/bin/thunar'):
                if not os.path.exists(manager):
                    continue

                cmd = ['su', pwd.getpwuid(self.uid)[0], '-c', '%s "%s"' % \
                    (manager, os.path.abspath(os.curdir))]
                if subprocess.call(cmd) == 0:
                    break

            return DONE

        def ok_clean():
            set_cleaning_status()
            _exec('lh_clean --chroot --stage --source --cache',
                'rm -rf config/ binary/ tftpboot/',
                'chown -R %d:%d .' % (self.uid, self.gid))
            return OK

        def failed():
            self.view.set_build_titles(_("Error when building Debian Live system"),
                _("There was an error when building your Debian Live system."))
            return DONE

        def failed_clean():
            set_cleaning_status()
            _exec('lh_clean --purge', 'rm -rvf config/',
                'chown -R %d:%d .' % (self.uid, self.gid))
            return FAILED

        def cancelled():
            self.view.set_build_titles(_("Build process cancelled"),
                _("The creation of your Debian Live system was cancelled."))
            return DONE

        def cancelled_clean():
            set_cleaning_status()
            _exec('lh_clean --purge', 'rm -rvf $(pwd)')
            return CANCELLED

        if self.state == BUILDING:
            self.state = FAILED_CLEAN
            try:
                f = open(STATUS_FILE)
                try:
                    if f.read().strip() == 'ok':
                        self.state = OK_CLEAN
                        self.build_successful = True
                finally:
                    f.close()
            except:
                pass

        self.state = {
            CANCELLED: cancelled,
            CANCELLED_CLEAN: cancelled_clean,
            FAILED: failed,
            FAILED_CLEAN: failed_clean,
            OK: ok,
            OK_CLEAN: ok_clean,
        }[self.state]()

        if self.state == DONE:
            self.view.set_build_status_change(initial=False)
            self.pid = -1

        # Auto-close if requested
        if self.view.get_build_auto_close() and self.build_successful:
            self.view.do_hide_window_build()

    def do_pulse_cb(self, *args):
        if self.state != DONE:
            self.view.do_build_pulse()
            return True

    def on_button_build_close_clicked(self, *args):
        self.view.do_hide_window_build()

    def on_button_build_cancel_clicked(self, *args):
        self.state = CANCELLED_CLEAN
        subprocess.call(['/bin/kill', '-s', 'KILL', '-%d' % self.pid])