from qt import *
from qttable import *
from releaseWizardBA import ReleaseWizardBA
from constants import *
import logging
import os
from ReleaseDataVO import ReleaseDataVO
from FileVO import FileVO
from messageQueue import progressMessageQueue
from workerThread import WorkerThread
from help import Help
import time
try:
# python2.4
set = set
except:
# python2.3 compatibility
from sets import Set
set = Set
debug = logging.getLogger("releaseWizard").debug
error = logging.getLogger("releaseWizard").error
COL_BASENAME = 0
COL_CPU = 1
COL_FILE_TYPE = 2
COL_FILENAME = 3
class ReleaseWizard(ReleaseWizardBA):
def __init__(self, parent, settings, sf_comm, projectVO, packageVO):
ReleaseWizardBA.__init__(self)
self.parent = parent
self.settings = settings
self.sf_comm = sf_comm
self.projectVO = projectVO
self.packageVO = packageVO
self.group_id = None
self.package_id = None
self.release_id = None
self.timer = QTimer(self)
self.connect(self.timer, SIGNAL("timeout()"),
self.getProgressMsg)
self.connect(self, SIGNAL("selected(const QString &)"), self.pageChanged)
self.setCaption("Create new %s release" % packageVO.getPackageName())
self.releaseNameEdited(self.newReleaseNameLineEdit.text())
self.release_notes_path = ""
self.change_log_path = ""
self.release_files_path = ""
self.selected_files = set()
self.releaseFilesTable.setColumnReadOnly(COL_BASENAME, True)
self.releaseFilesTable.setColumnReadOnly(COL_FILENAME, True)
self.releaseFilesTable.setLeftMargin(0)
self.populateProcessorCombo()
self.releaseFilesTable.hideColumn(COL_FILENAME)
self.connect(self.releaseFilesTable,
SIGNAL("contextMenuRequested(int,int,const QPoint&)"),
self.fileMenu)
self.releaseVO = None
self.thread = None
self.eventDict = {EVENT_CREATE_RELEASE: self.upload_files,
EVENT_UPLOAD_FILES: self.edit_event_step1,
EVENT_EDIT_RELEASE_1: self.edit_event_step2,
EVENT_EDIT_RELEASE_2: self.edit_event_step3,
EVENT_EDIT_RELEASE_3: self.edit_event_step4,
EVENT_EDIT_RELEASE_4: self.complete}
self.successful_completion = False
self.cancelled = False
def customEvent(self, event):
data = event.data()
etype = event.type()
#print etype
event_action = self.eventDict.get(etype)
if event_action: event_action(data)
def __wait(self):
if not self.thread: return
while self.thread.running():
debug("waiting for thread to complete...")
time.sleep(0.25)
def releaseNameEdited(self, text):
releasePage = self.page(WIZARD_PAGE_RELEASE_NAME)
if str(text):
self.setNextEnabled(releasePage, True)
else:
self.setNextEnabled(releasePage, False)
def help(self):
#debug("help for page #: %d", self.indexOf(self.currentPage()))
page_num = self.indexOf(self.currentPage())
self._help = Help(self, WIZARD_HELP_PAGES[page_num])
def __importFile(self, filename, widget):
try:
fp = open(filename, "r")
data = fp.read()
fp.close()
try:
widget.setWordWrap(0)
except:
pass
widget.setText(data)
return 1
except Exception, e:
QMessageBox.warning(self,
"Could not read from input file\n%s" % str(e))
return 0
def importChangeLog(self):
self.changeLogPushButton.setOn(False)
self.changeLogPushButton.setDown(False)
fn = QFileDialog.getOpenFileName(self.change_log_path or self.release_notes_path,
None,
self,
"Import Change Log",
"Import Change Log")
fn = str(fn)
if not fn: return
if self.__importFile(fn, self.changeLogTextEdit):
self.change_log_path = fn
def importReleaseNotes(self):
self.releaseNotesPushButton.setOn(False)
self.releaseNotesPushButton.setDown(False)
fn = QFileDialog.getOpenFileName(self.release_notes_path or self.change_log_path,
None,
self,
"Import Release Notes",
"Import Release Notes")
fn = str(fn)
if not fn: return
if self.__importFile(fn, self.releaseNotesTextEdit):
self.release_notes_path = fn
def populateProcessorCombo(self):
data = self.__getProcessorComboData()
self.processorComboBox.insertStringList(data)
def __getProcessorComboData(self):
keys = CPU.keys()
keys.sort()
strlist = QStringList()
#strlist.append("")
for key in keys:
strlist.append(key)
return strlist
def __getFileTypeComboData(self):
keys = FILE_TYPE.keys()
keys.sort()
strlist = QStringList()
#strlist.append("")
for key in keys:
strlist.append(key)
return strlist
def __guessFileType(self, filename):
parts = filename.split(".")
lparts = len(parts)
if lparts == 1:
exts = []
elif lparts == 2:
exts = [".%s" % parts[1]]
else:
exts = [".%s.%s" % (parts[-2], parts[-1]), ".%s" % parts[-1]]
guess = None
for ext in exts:
guess = FILE_TYPE_GUESS.get(ext)
if guess: break
if not guess: guess = "Other"
debug("guess: %s is type: %s", filename, guess)
return guess
## def __addApplyAllRow(self):
## rownum = 0
## self.releaseFilesTable.setNumRows(rownum+1)
## cpuData = self.__getProcessorComboData()
## cpuData.prepend("Apply To All")
## cpuCombo = QComboTableItem(self.releaseFilesTable,
## cpuData)
## self.releaseFilesTable.setItem(rownum, COL_CPU, cpuCombo)
## for colnum in range(self.releaseFilesTable.numCols()):
## rect = self.releaseFilesTable.cellRect(rownum, colnum);
## pix = QPixmap(rect.width() * 5, rect.height())
## color = Qt.gray
## pix.fill(color)
## self.releaseFilesTable.setPixmap(rownum, colnum, pix)
## self.releaseFilesTable.setPixmap(rownum+1, colnum, pix)
def updateProcessor(self, name):
sname = str(name)
debug("updateProcessor(): %s", sname)
if sname in ('Choose...', ''): return
rownum = self.releaseFilesTable.numRows()
for i in range(rownum):
cpuCombo = self.releaseFilesTable.item(i, COL_CPU)
cpuCombo.setCurrentItem(name)
if self.__validateFiles(rownum):
self.setNextEnabled(self.page(WIZARD_PAGE_FILE_SELECTION), True)
def addFiles(self):
self.addFilesPushButton.setOn(False)
self.addFilesPushButton.setDown(False)
files = QFileDialog.getOpenFileNames(None,
self.release_files_path,
self,
"Add Files",
"Add Files")
if files:
self.processorComboBox.setEnabled(True)
rownum = self.releaseFilesTable.numRows()
for f in files:
fstr = str(f)
if fstr in self.selected_files: continue
else: self.selected_files.add(fstr)
self.releaseFilesTable.setNumRows(rownum+1)
filename = os.path.basename(fstr)
self.releaseFilesTable.setText(rownum, COL_BASENAME, filename)
cpuData = self.__getProcessorComboData()
cpuCombo = QComboTableItem(self.releaseFilesTable,
cpuData)
cpuCombo.setCurrentItem("Any")
self.releaseFilesTable.setItem(rownum, COL_CPU, cpuCombo)
fileTypeData = self.__getFileTypeComboData()
fileTypeCombo = QComboTableItem(self.releaseFilesTable,
fileTypeData)
fileTypeCombo.setCurrentItem(self.__guessFileType(filename))
self.releaseFilesTable.setItem(rownum, COL_FILE_TYPE, fileTypeCombo)
## self.releaseFilesTable.setItem(rownum,
## COL_DELETE,
## QCheckTableItem(self.releaseFilesTable,""))
self.releaseFilesTable.setText(rownum, COL_FILENAME, fstr)
rownum += 1
self.__resizeColumn(COL_BASENAME)
self.__resizeColumn(COL_CPU)
self.__resizeColumn(COL_FILE_TYPE)
if rownum > 0:
self.setNextEnabled(self.page(WIZARD_PAGE_FILE_SELECTION), True)
# if self.__validateFiles(rownum):
# self.setNextEnabled(self.page(WIZARD_PAGE_FILE_SELECTION), True)
def __validateFiles(self, rownum=None):
if not rownum: rownum = self.releaseFilesTable.numRows()
ok = True
for i in range(rownum):
cpuCombo = self.releaseFilesTable.item(i, COL_CPU)
cpuStr = str(cpuCombo.currentText())
if cpuStr in (None, ''): return False
typeCombo = self.releaseFilesTable.item(i, COL_FILE_TYPE)
typeStr = str(typeCombo.currentText())
if typeStr in (None, ''): return False
return True
def __resizeColumn(self, colnum):
self.releaseFilesTable.adjustColumn(colnum)
width = self.releaseFilesTable.columnWidth(colnum)
self.releaseFilesTable.setColumnWidth(colnum, width + 5)
def fileMenu(self, row, col, qpt):
self.file_menu = QPopupMenu(self)
self.file_menu.insertItem("Remove files",
self.removeFiles)
self.file_menu.popup(QCursor.pos())
def removeFiles(self):
# removes selected files from the fileselection table
numsel = self.releaseFilesTable.numSelections()
rows = []
for i in range(numsel):
tsel = self.releaseFilesTable.selection(i)
for rownum in range(tsel.topRow(), tsel.bottomRow()+1):
rows.append(rownum)
filename = str(self.releaseFilesTable.text(rownum, COL_FILENAME))
self.selected_files.remove(filename)
# delete rows in reverse sorted order
rows.sort()
rows.reverse()
for rownum in rows:
self.releaseFilesTable.removeRow(rownum)
if self.releaseFilesTable.numRows() == 0:
self.processorComboBox.setEnabled(False)
#self.setNextEnabled(self.page(WIZARD_PAGE_FILE_SELECTION), False)
self.setNextEnabled(self.page(WIZARD_PAGE_FILE_SELECTION), False)
def getReleaseData(self):
files = []
for rownum in range(self.releaseFilesTable.numRows()):
fullpath = str(self.releaseFilesTable.text(rownum, COL_FILENAME))
filename = str(self.releaseFilesTable.text(rownum, COL_BASENAME))
processor = str(self.releaseFilesTable.text(rownum, COL_CPU))
filetype = str(self.releaseFilesTable.text(rownum, COL_FILE_TYPE))
files.append(FileVO(fullpath,
filename,
processor,
CPU.get(processor),
filetype,
FILE_TYPE.get(filetype)))
releaseVO = ReleaseDataVO(self.projectVO,
self.packageVO)
releaseVO.setName(str(self.newReleaseNameLineEdit.text()))
releaseVO.setNotifyUsers(self.releaseNotifyCheckBox.isChecked())
releaseVO.setChangeLog(str(self.changeLogTextEdit.text()))
releaseVO.setReleaseNotes(str(self.releaseNotesTextEdit.text()))
releaseVO.setFiles(files)
return releaseVO
def __getTotalSteps(self):
num = 0
num += self.releaseFilesTable.numRows() * 2 # file u/l & step 3
num += 1 # create release
num += 1 # step 1
num += 1 # step 2
num += 1 # step 4
num += 1
return num
def pageChanged(self, pageName):
currPage = self.currentPage()
pageNum = self.indexOf(currPage)
if pageNum == WIZARD_PAGE_RELEASE_NAME:
if str(self.newReleaseNameLineEdit.text()): enable = True
else: enable = False
self.setNextEnabled(currPage, enable)
elif pageNum == WIZARD_PAGE_FILE_SELECTION:
self.setNextEnabled(currPage, self.releaseFilesTable.numRows() != 0)
elif pageNum == WIZARD_PAGE_PROGRESS:
self.progressBar.setProgress(0)
self.progressBar.setTotalSteps(self.__getTotalSteps())
self.progressTextLabel.setText("Press the 'finish' button to create your SourceForge release")
self.setFinishEnabled(currPage, True)
####################################################################################
# Progress-related code
####################################################################################
def getProgressMsg(self):
# read the message queue. If an item exists,
# populate the progress label with it.
msg = progressMessageQueue.get()
if msg:
self.progressTextLabel.setText(msg)
self.progressBar.setProgress(self.progressBar.progress()+1)
def isCancelled(self):
return self.cancelled
def accept(self):
if self.successful_completion: ReleaseWizardBA.accept(self)
else:
page = self.page(WIZARD_PAGE_PROGRESS)
self.releaseVO = self.getReleaseData()
self.initializeProgessPage()
self.group_id = self.releaseVO.getProjectVO().getGroupId()
self.package_id = self.releaseVO.getPackageVO().getPackageId()
self.setBackEnabled(page, False)
self.setFinishEnabled(page, False)
self.timer.start(500, False)
self.cancelled = False
self.create_release()
def success():
ReleaseWizardBA.accept(self)
def reject(self):
debug("Operation cancelled by user")
# perhaps hide the release?
self.cancelled = True
ReleaseWizardBA.reject(self)
def create_release(self):
self.createReleaseTextLabel.setEnabled(True)
self.__wait()
if self.cancelled: return
self.thread = WorkerThread(self,
EVENT_CREATE_RELEASE,
self.sf_comm.add_release,
self.group_id,
self.package_id,
self.releaseVO.getName())
self.thread.start()
def upload_files(self, data):
self.uploadFilesTextLabel.setEnabled(True)
debug("now entering upload_files: %s", data)
if not data:
self.error("Could not create release")
return
self.release_id = data
fileVOs = self.releaseVO.getFiles()
self.__wait()
if self.cancelled: return
self.thread = WorkerThread(self,
EVENT_UPLOAD_FILES,
self.sf_comm.upload_files,
self,
fileVOs)
self.thread.start()
def edit_event_step1(self, data):
self.changeLogTextLabel.setEnabled(True)
self.releaseNotesTextLabel.setEnabled(True)
debug("now entering edit_event_step1: %s", data)
release_notes = self.releaseVO.getReleaseNotes()
change_log = self.releaseVO.getChangeLog()
if not release_notes and not change_log:
self.edit_event_step2(True)
return
self.__wait()
if self.cancelled: return
self.thread = WorkerThread(self,
EVENT_EDIT_RELEASE_1,
self.sf_comm.edit_release_step1,
self.group_id,
self.package_id,
self.release_id,
self.releaseVO.getName(),
self.releaseVO.getReleaseNotes(),
self.releaseVO.getChangeLog())
self.thread.start()
def edit_event_step2(self, ok):
self.selectFilesTextLabel.setEnabled(True)
debug("now entering edit_event_step2: %s", ok)
self.__wait()
if self.cancelled: return
if not ok:
self.error("Unable to add release notes/change log")
return
self.thread = WorkerThread(self,
EVENT_EDIT_RELEASE_2,
self.sf_comm.edit_release_step2,
self.group_id,
self.package_id,
self.release_id,
self.releaseVO.getFiles())
self.thread.start()
def edit_event_step3(self, data_tuple):
self.fileAttribTextLabel.setEnabled(True)
lookup_dict = data_tuple[0]
ok = data_tuple[1]
if not ok:
self.error("Unable to select file for inclusion")
return
debug("edit_event_step3: %s - %s", lookup_dict, ok)
self.__wait()
if self.cancelled: return
self.thread = WorkerThread(self,
EVENT_EDIT_RELEASE_3,
self.sf_comm.edit_release_step3,
self.group_id,
self.package_id,
self.release_id,
self.releaseVO.getFiles(),
lookup_dict)
self.thread.start()
def edit_event_step4(self, ok):
self.notifyTextLabel.setEnabled(True)
debug("edit_event_step4: %s", ok)
self.__wait()
if self.cancelled: return
if not ok:
self.error("Unable to update file attributes")
return
if not self.releaseVO.getNotifyUsers(): self.complete(None)
self.thread = WorkerThread(self,
EVENT_EDIT_RELEASE_4,
self.sf_comm.edit_release_step4,
self.group_id,
self.package_id,
self.release_id)
self.thread.start()
def error(self, msg):
self.timer.stop()
page = self.page(WIZARD_PAGE_PROGRESS)
self.progressTextLabel.setText(msg)
self.setFinishEnabled(page, False)
self.setBackEnabled(page, True)
self.successful_completion = False
def complete(self, data):
self.timer.stop()
page = self.page(WIZARD_PAGE_PROGRESS)
self.progressTextLabel.setText("Successfully created new release")
self.progressBar.setProgress(self.progressBar.totalSteps())
self.setFinishEnabled(page, True)
self.setBackEnabled(page, False)
self.successful_completion = True
def initializeProgessPage(self):
if self.releaseVO.getNotifyUsers():
self.notifyTextLabel.show()
else:
self.notifyTextLabel.hide()
self.createReleaseTextLabel.setEnabled(False)
self.uploadFilesTextLabel.setEnabled(False)
self.changeLogTextLabel.setEnabled(False)
self.releaseNotesTextLabel.setEnabled(False)
self.selectFilesTextLabel.setEnabled(False)
self.fileAttribTextLabel.setEnabled(False)
self.notifyTextLabel.setEnabled(False)
|