def task_create(project_name: str, title: str, description: str = None): """Create new task.""" project_data = database.get_project_by_name(name=project_name) project = Project(id=project_data[0][0], name=project_data[0][1], description=project_data[0][2]) task = Task(id=None, title=title, description=description, status=TaskStatusE.OPEN, project_id=project.id) database.create_task(task) typer.echo(f"Task created: {title} in project {project.name}")
def project_list(): """List of the available projects.""" projects = [ Project(id=row[0], name=row[1], description=row[2]) for row in database.get_project_list() ] if not projects: typer.echo("No projects defined.") return for project in projects: typer.echo( f"Project: {project.name}, description: {project.description}, ID: {project.id}" )
def task_show(task_id: int): """Show the task details with task_id.""" task_data = database.get_task_by_id(task_id=task_id) task = Task(id=task_data[0][0], title=task_data[0][1], description=task_data[0][2], status=task_data[0][3], project_id=task_data[0][4]) project_data = database.get_project_by_id(project_id=task.project_id) project = Project(id=project_data[0][0], name=project_data[0][1], description=project_data[0][2]) typer.echo( f"Task: {task.title}, status: {task.get_display_status()}, description: {task.description}, " f"project: {project.name}/{project.id}")
def task_list(project_name: str): """List of the available tasks in given project.""" project_data = database.get_project_by_name(name=project_name) project = Project(id=project_data[0][0], name=project_data[0][1], description=project_data[0][2]) tasks = [ Task(id=row[0], title=row[1], description=row[2], status=row[3], project_id=row[4]) for row in database.get_task_list(project_id=project.id) ] if not tasks: typer.echo(f"No tasks defined for project {project.name}.") return for task in tasks: typer.echo( f"Task: {task.title}, status: {task.get_display_status()}, description: {task.description}, " f"project: {project.name}/{project.id}")
def __init__(self): QtGui.QMainWindow.__init__(self) self.setAcceptDrops(True) self.dropped.connect(self.importAsLayer) self.project = Project(self) self.toolsWidget = ToolsWidget(self.project) self.optionsWidget = OptionsWidget(self.project) self.paletteWidget = PaletteWidget(self.project) self.onionSkinWidget = OnionSkinWidget(self.project) self.timelineWidget = TimelineWidget(self.project) self.scene = Scene(self.project) self.updateTitle() self.project.updateTitleSign.connect(self.updateTitle) ### layout ##################################################### self.setDockNestingEnabled(True) self.setCentralWidget(self.scene) QtGui.QApplication.setOrganizationName("pixeditor") QtGui.QApplication.setApplicationName("pixeditor") settings = QtCore.QSettings() settings.beginGroup("mainWindow") try: lock = bool(int(settings.value("lock"))) except TypeError: lock = True toolsDock = Dock(self.toolsWidget, "tools", lock) toolsDock.setObjectName("toolsDock") self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, toolsDock) self.scene.coords=toolsDock.widget().coords optionsDock = Dock(self.optionsWidget, "options", lock) optionsDock.setObjectName("optionsDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, optionsDock) paletteDock = Dock(self.paletteWidget, "palette", lock) paletteDock.setObjectName("paletteDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, paletteDock) onionSkinDock = Dock(self.onionSkinWidget, "onion skin", lock) onionSkinDock.setObjectName("onionSkinDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, onionSkinDock) timelineDock = Dock(self.timelineWidget, "timeline", lock) timelineDock.setObjectName("timelineDock") self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, timelineDock) ### File menu ### menubar = self.menuBar() openAction = QtGui.QAction('Open', self) openAction.triggered.connect(self.openAction) saveAsAction = QtGui.QAction('Save as', self) saveAsAction.triggered.connect(self.saveAsAction) saveAction = QtGui.QAction('Save', self) saveAction.triggered.connect(self.saveAction) saveAction.setShortcut('Ctrl+S') importNewAction = QtGui.QAction('Import as new', self) importNewAction.triggered.connect(self.importAsNewAction) importLayerAction = QtGui.QAction('Import as layer', self) importLayerAction.triggered.connect(self.importAsLayerAction) exportAction = QtGui.QAction('Export', self) exportAction.triggered.connect(self.exportAction) exportAction.setShortcut('Ctrl+E') exitAction = QtGui.QAction('Exit', self) exitAction.triggered.connect(self.close) exitAction.setShortcut('Ctrl+Q') fileMenu = menubar.addMenu('File') fileMenu.addAction(openAction) fileMenu.addAction(saveAsAction) fileMenu.addAction(saveAction) fileMenu.addSeparator() fileMenu.addAction(importNewAction) fileMenu.addAction(importLayerAction) fileMenu.addAction(exportAction) fileMenu.addSeparator() fileMenu.addAction(exitAction) ### Edit menu ### undoAction = QtGui.QAction('Undo', self) undoAction.triggered.connect(self.project.undo) undoAction.setShortcut('Ctrl+Z') redoAction = QtGui.QAction('Redo', self) redoAction.triggered.connect(self.project.redo) redoAction.setShortcut('Ctrl+Y') cutAction = QtGui.QAction('Cut', self) cutAction.triggered.connect(self.timelineWidget.cut) cutAction.setShortcut('Ctrl+X') copyAction = QtGui.QAction('Copy', self) copyAction.triggered.connect(self.timelineWidget.copy) copyAction.setShortcut('Ctrl+C') pasteAction = QtGui.QAction('Paste', self) pasteAction.triggered.connect(self.timelineWidget.paste) pasteAction.setShortcut('Ctrl+V') editMenu = menubar.addMenu('Edit') editMenu.addAction(undoAction) editMenu.addAction(redoAction) editMenu.addSeparator() editMenu.addAction(cutAction) editMenu.addAction(copyAction) editMenu.addAction(pasteAction) ### project menu ### newAction = QtGui.QAction('New', self) newAction.triggered.connect(self.newAction) cropAction = QtGui.QAction('Crop', self) cropAction.triggered.connect(self.cropAction) resizeAction = QtGui.QAction('Resize', self) resizeAction.triggered.connect(self.resizeAction) replacePaletteAction = QtGui.QAction('replace palette', self) replacePaletteAction.triggered.connect(self.replacePaletteAction) prefAction = QtGui.QAction('Background', self) prefAction.triggered.connect(self.backgroundAction) projectMenu = menubar.addMenu('Project') projectMenu.addAction(newAction) projectMenu.addAction(cropAction) projectMenu.addAction(resizeAction) projectMenu.addAction(replacePaletteAction) projectMenu.addAction(prefAction) ### resources menu ### savePaletteAction = QtGui.QAction('save current palette', self) savePaletteAction.triggered.connect(self.savePaletteAction) savePenAction = QtGui.QAction('save custom pen', self) savePenAction.triggered.connect(self.savePenAction) reloadResourcesAction = QtGui.QAction('reload resources', self) reloadResourcesAction.triggered.connect(self.reloadResourcesAction) resourcesMenu = menubar.addMenu('Resources') resourcesMenu.addAction(savePaletteAction) resourcesMenu.addAction(savePenAction) resourcesMenu.addAction(reloadResourcesAction) ### view menu ### viewMenu = menubar.addMenu('View') dockWidgets = self.findChildren(QtGui.QDockWidget) for dock in dockWidgets: viewMenu.addAction(dock.toggleViewAction()) viewMenu.addSeparator() self.lockLayoutWidget = QtGui.QAction('Lock Layout', self) self.lockLayoutWidget.setCheckable(True) self.lockLayoutWidget.setChecked(lock) self.lockLayoutWidget.toggled.connect(self.lockLayoutAction) viewMenu.addAction(self.lockLayoutWidget) ### shortcuts ### QtGui.QShortcut(QtCore.Qt.Key_Left, self, lambda : self.selectFrame(-1)) QtGui.QShortcut(QtCore.Qt.Key_Right, self, lambda : self.selectFrame(1)) QtGui.QShortcut(QtCore.Qt.Key_Up, self, lambda : self.selectLayer(-1)) QtGui.QShortcut(QtCore.Qt.Key_Down, self, lambda : self.selectLayer(1)) QtGui.QShortcut(QtCore.Qt.Key_Space, self, self.timelineWidget.playPauseClicked) QtGui.QShortcut(QtCore.Qt.Key_1, self, toolsDock.widget().penClicked) QtGui.QShortcut(QtCore.Qt.Key_2, self, toolsDock.widget().pipetteClicked) QtGui.QShortcut(QtCore.Qt.Key_3, self, toolsDock.widget().fillClicked) QtGui.QShortcut(QtCore.Qt.Key_4, self, toolsDock.widget().moveClicked) QtGui.QShortcut(QtCore.Qt.Key_5, self, toolsDock.widget().selectClicked) self.hiddenDock = [] QtGui.QShortcut(QtCore.Qt.Key_Tab, self, self.hideDock) QtGui.QShortcut(QtCore.Qt.Key_E, self, self.project.changeColor) ### settings ### try: self.restoreGeometry(settings.value("geometry")) except TypeError: pass # no geometry to restore so leave as is try: self.restoreState(settings.value("windowState")) except TypeError: pass # no state to restore so leave as is settings.endGroup() self.show()
def __init__(self, workingDir): self.workingDir = workingDir self.project = Project()
def project_create(project_name: str, description: str = None): """Create the new project.""" project = Project(id=None, name=project_name, description=description) database.create_project(project) typer.echo(f"Project `{project_name}` created.")
def disassemble_and_make_project(INPUT_PATH, project_dir: Path, disassembler_db: DisassemblerDb): build_dir = project_dir / "build" gen_asm_dir = project_dir / "gen-asm" # create output directories # TODO: gen_asm_dir should be emptied, since cluster boundaries can change between runs for dir in {project_dir, build_dir, gen_asm_dir}: dir.mkdir(parents=True, exist_ok=True) prj = Project(INPUT_PATH, project_dir, disassembler_db_snapshot=deepcopy(disassembler_db)) pe = pefile.PE(INPUT_PATH) exe_patch_offset = pe.sections[0].PointerToRawData clusters = data_io.load_clusters(project_dir / "tmp-clusters") labels_db = data_io.load_labels(project_dir, suffix=".tmp") print(f"Disassembling {len(clusters)} clusters...") for cluster in clusters: filename = gen_asm_dir / f"{cluster.section_name[1:]}_{cluster.start:08X}.s" print(f" - {filename} : {len(cluster.chunks)} chunks") if cluster.start < MIN_OFFSET: continue total_length = sum([len(chunk.bytes) for chunk in cluster.chunks]) cluster_end = cluster.start + total_length with open(filename, 'wt') as f: if AS == "gas": print(f"""\ .intel_syntax .section {cluster.section_name} """, file=f) # export labels for label in sorted(labels_db.values()): if label.address >= cluster_end: break elif label.address >= cluster.start: print( f".global {gnuas_escape_label(label.name):40s} /* {label} */", file=f) print(file=f) disassembly_gas.disassemble_for_GAS( cluster.chunks, f, disassembler_db=disassembler_db, labels_db=labels_db, use_labels=True) if AS == "nasm": print(f"""\ section {cluster.section_name} """, file=f) analysis.disassemble_for_nasm(cluster.chunks, f, labels_db=labels_db, use_labels=True) prj.add_asm_source(filename, cluster.start, total_length) # Generate MinGW project def relpath(path_to, path_from): path_to = Path(path_to).resolve() path_from = Path(path_from).resolve() try: for p in (*reversed(path_from.parents), path_from): head, tail = p, path_to.relative_to(p) except ValueError: # Stop when the paths diverge. pass return Path( '../' * (len(path_from.parents) - len(head.parents))).joinpath(tail) def generate_project(prj: Project): # generate project Makefile project_makefile = project_dir / "Makefile" P = PurePosixPath makefile_cwd = project_dir # relative_source_dir = Path().relative_to(self.output_dir) build_dir_rel = relpath(build_dir, makefile_cwd) input_exe_path = relpath(prj.exe_path, makefile_cwd) prj.output_path = relpath(project_dir / prj.exe_path.name, makefile_cwd) ldscript = relpath("i386pe.x", makefile_cwd) with open(project_makefile, "wt", newline='\n') as f: all_obj = [] for src in prj.sources: obj_path = relpath(build_dir / src.path.stem, makefile_cwd).with_suffix(".o") all_obj.append(obj_path) # link objects obj_paths = " ".join([str(P(obj_path)) for obj_path in all_obj]) # FIXME: un-hardcode! text_start = 0x10001000 print(f""" #PREFIX=i686-w64-mingw32- AS=$(PREFIX)as LD=$(PREFIX)ld OBJCOPY=$(PREFIX)objcopy OBJDUMP=$(PREFIX)objdump ALLCODE_BIN={P(build_dir_rel)}/allcode.bin ALLCODE_O={P(build_dir_rel)}/allcode.o ALLCODE_S={P(build_dir_rel)}/allcode.s OUTPUT_EXE={P(prj.output_path)} OUTPUT_S={P(build_dir_rel)}/output.s COPY_WITH_PATCH={P(relpath("copy_with_patch.py", project_dir))} all: input.s $(OUTPUT_EXE) $(OUTPUT_S) input.s: {P(input_exe_path)} \t$(OBJDUMP) -M intel -D -h $< | tail -n +3 >$@ $(ALLCODE_O): {obj_paths} {P(ldscript)} \tar rcs {P(build_dir_rel)}/allcode.a {obj_paths} \t$(LD) -T {P(ldscript)} -Ttext=0x{text_start:08x} {obj_paths} -o $@ \t$(OBJDUMP) -M intel -D -h $(ALLCODE_O) >$(ALLCODE_S) $(ALLCODE_BIN): $(ALLCODE_O) \t$(OBJCOPY) --only-section=.text -O binary $< $@ $(OUTPUT_EXE): $(ALLCODE_BIN) {P(input_exe_path)} \t$(COPY_WITH_PATCH) {P(input_exe_path)} $@ {exe_patch_offset} $(ALLCODE_BIN) \t#cp {P(input_exe_path)} $@ \t#dd if=$(ALLCODE_BIN) of=$@ obs=1 seek={exe_patch_offset} conv=notrunc 2>&1 $(OUTPUT_S): $(OUTPUT_EXE) \t$(OBJDUMP) -M intel -D -h $< | tail -n +3 >$@ """, file=f) for src in prj.sources: src_path = relpath(src.path, makefile_cwd) obj_path = relpath(build_dir / src.path.stem, makefile_cwd).with_suffix(".o") # TODO DRY print(f"{P(obj_path)}: {P(src_path)}", file=f) if AS == "gas": print(f"\t$(AS) $< -o $@", file=f) print(file=f) # all_obj = [] # # for src in prj.sources: # if src.offset < MIN_OFFSET: continue # # # patch_offset = src.offset + prj.text_vma_to_file_offset # # print(f"makeproject: {src.path} @ {src.offset:08X}h") # # # strategy: compile asm source to .o, export as flat binary, patch exe file (diff in the end) # src_path = relpath(src.path, makefile_cwd) # obj1_path = relpath(prj.output_dir / (src.path.stem + "a"), makefile_cwd).with_suffix(".o") # obj_path = relpath(prj.output_dir / src.path.stem, makefile_cwd).with_suffix(".o") # dasm_path = relpath(prj.output_dir / src.path.stem, makefile_cwd).with_suffix(".s") # bin_path = relpath(prj.output_dir / src.path.stem, makefile_cwd).with_suffix(".bin") # # # print(f"# cluster {src.offset:08X}h: {src.length:6} bytes @ {patch_offset:X}h", file=f) # # if AS == "nasm": # print(f"nasm {P(src_path)} -f elf32 -o {P(obj_path)}", file=f) # #print(f"$LD -Ttext=0x{src.offset:08X} {P(obj1_path)} -o {P(obj_path)}", file=f) # # print(f"$OBJDUMP -M intel -D {P(obj_path)} >{P(dasm_path)}", file=f) # # print(f"$OBJCOPY --only-section=.text -O binary {P(obj_path)} {P(bin_path)}", file=f) # # print(f"dd if={P(bin_path)} of={P(prj.output_path)} obs=1 seek={patch_offset} conv=notrunc", file=f) # # print(file=f) # # all_obj.append(obj_path) #break # print(f""" # # post-diff # cmp -l {P(input_exe_path)} {P(prj.output_path)} | gawk '{{printf "%08X %02X %02X\\n", $1, strtonum(0$2), strtonum(0$3)}}' # """, file=f) # generate linker script # ndisasm bigobj & compare # print(f"ndisasm bigobj.bin -b 32 -o 0x401000 >bigobj.asm", file=f) generate_project(prj) return prj