Started moving fossil operations into Bridge
FossilOrigin-Name: 7a4ea959c64034b6e20dec41a4a8c16a09397bfa
This commit is contained in:
		
							
								
								
									
										6
									
								
								fuel.pro
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								fuel.pro
									
									
									
									
									
								
							| @@ -51,7 +51,8 @@ SOURCES += src/main.cpp\ | |||||||
| 	src/CloneDialog.cpp \ | 	src/CloneDialog.cpp \ | ||||||
| 	src/LoggedProcess.cpp \ | 	src/LoggedProcess.cpp \ | ||||||
| 	src/BrowserWidget.cpp \ | 	src/BrowserWidget.cpp \ | ||||||
| 	src/CustomWebView.cpp | 	src/CustomWebView.cpp \ | ||||||
|  |     src/Bridge.cpp | ||||||
|  |  | ||||||
| HEADERS  += src/MainWindow.h \ | HEADERS  += src/MainWindow.h \ | ||||||
| 	src/CommitDialog.h \ | 	src/CommitDialog.h \ | ||||||
| @@ -62,7 +63,8 @@ HEADERS  += src/MainWindow.h \ | |||||||
| 	src/CloneDialog.h \ | 	src/CloneDialog.h \ | ||||||
| 	src/LoggedProcess.h \ | 	src/LoggedProcess.h \ | ||||||
| 	src/BrowserWidget.h \ | 	src/BrowserWidget.h \ | ||||||
| 	src/CustomWebView.h | 	src/CustomWebView.h \ | ||||||
|  |     src/Bridge.h | ||||||
|  |  | ||||||
| FORMS    += ui/MainWindow.ui \ | FORMS    += ui/MainWindow.ui \ | ||||||
| 	ui/CommitDialog.ui \ | 	ui/CommitDialog.ui \ | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								manifest
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								manifest
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| C Create\snew\sbranch\snamed\s"refactor" | C Started\smoving\sfossil\soperations\sinto\sBridge\n | ||||||
| D 2015-04-26T09:57:06.445 | D 2015-04-26T10:36:55.373 | ||||||
| F .travis.yml 77966888a81c4ceee1fcc79bce842c9667ad8a35 | F .travis.yml 77966888a81c4ceee1fcc79bce842c9667ad8a35 | ||||||
| F debian/changelog eb4304dfcb6bb66850ec740838090eb50ce1249b | F debian/changelog eb4304dfcb6bb66850ec740838090eb50ce1249b | ||||||
| F debian/compat b6abd567fa79cbe0196d093a067271361dc6ca8b | F debian/compat b6abd567fa79cbe0196d093a067271361dc6ca8b | ||||||
| @@ -15,7 +15,7 @@ F dist/win/fuel.iss ef3558dbba409eb194938b930377fc9ee27d319e | |||||||
| F doc/Building.txt 17b43fa23da764b5d1b828cc48c5a95e612bbd8f | F doc/Building.txt 17b43fa23da764b5d1b828cc48c5a95e612bbd8f | ||||||
| F doc/Changes.txt b03302545e4a6c0b16a30d623a7627f8aef65ef6 | F doc/Changes.txt b03302545e4a6c0b16a30d623a7627f8aef65ef6 | ||||||
| F doc/License.txt 4cc77b90af91e615a64ae04893fdffa7939db84c | F doc/License.txt 4cc77b90af91e615a64ae04893fdffa7939db84c | ||||||
| F fuel.pro 844a18c3faf5239e0d0025d8b7feac3900c28e71 | F fuel.pro fe3ce3763affa5e809b1154fffd33b437d03ca5b | ||||||
| F intl/convert.bat 4222ae403418381452b843929d15259ea9850ab1 x | F intl/convert.bat 4222ae403418381452b843929d15259ea9850ab1 x | ||||||
| F intl/convert.sh 2ca2179ff53e727f241925b75e19182607883c45 x | F intl/convert.sh 2ca2179ff53e727f241925b75e19182607883c45 x | ||||||
| F intl/de_DE.ts e2faceab920ac60c97bbc6fba038e261d51fc741 | F intl/de_DE.ts e2faceab920ac60c97bbc6fba038e261d51fc741 | ||||||
| @@ -184,6 +184,8 @@ F rsrc/icons/fuel.icns 81e535004b62db801a02f3e15d0a33afc9d4070b | |||||||
| F rsrc/icons/fuel.ico eb529ab3332a17b9302ef3e851db5b9ebce2a038 | F rsrc/icons/fuel.ico eb529ab3332a17b9302ef3e851db5b9ebce2a038 | ||||||
| F rsrc/icons/fuel.png 40daf53b7f6bdcdd0d6aa5ef433d078ec5ea4342 | F rsrc/icons/fuel.png 40daf53b7f6bdcdd0d6aa5ef433d078ec5ea4342 | ||||||
| F rsrc/resources.qrc 4098be128fd6c045db933d041fe8844b14643a6f | F rsrc/resources.qrc 4098be128fd6c045db933d041fe8844b14643a6f | ||||||
|  | F src/Bridge.cpp b34f14d8d887c9db6b27a84b6423931bf262e7a0 | ||||||
|  | F src/Bridge.h a2167ed1bb8d1d80eb2ff0fda157eb4c8d176b16 | ||||||
| F src/BrowserWidget.cpp 8b8f545cdff4a4188edc698a1b4777f5df46f056 | F src/BrowserWidget.cpp 8b8f545cdff4a4188edc698a1b4777f5df46f056 | ||||||
| F src/BrowserWidget.h 764d66aa9a93b890298bd0301097739cb4e16597 | F src/BrowserWidget.h 764d66aa9a93b890298bd0301097739cb4e16597 | ||||||
| F src/CloneDialog.cpp 812ef7d361c16da21540b7047c9d4d5e74f18539 | F src/CloneDialog.cpp 812ef7d361c16da21540b7047c9d4d5e74f18539 | ||||||
| @@ -198,13 +200,13 @@ F src/FileTableView.cpp 5ddf8c391c9a3ac449ec61fb1db837b577afeec2 | |||||||
| F src/FileTableView.h 03e56d87c2d46411b9762b87f4d301619aaf18df | F src/FileTableView.h 03e56d87c2d46411b9762b87f4d301619aaf18df | ||||||
| F src/LoggedProcess.cpp 2a1e5c94bc1e57c8984563e66c210e43a14dc60c | F src/LoggedProcess.cpp 2a1e5c94bc1e57c8984563e66c210e43a14dc60c | ||||||
| F src/LoggedProcess.h 85df7c635c807a5a0e8c4763f17a0752aaff7261 | F src/LoggedProcess.h 85df7c635c807a5a0e8c4763f17a0752aaff7261 | ||||||
| F src/MainWindow.cpp f023407f57730b695d4eeff8f27eef569c9eec66 | F src/MainWindow.cpp 7d07c97213b1a448d0a850c017cf226fb1c553da | ||||||
| F src/MainWindow.h dc0a9ed7de8a338e56c38c00ec303796f31bd24d | F src/MainWindow.h a69b2e5ad3e6cd42343bccf145fa99dc9eb6c4f2 | ||||||
| F src/SettingsDialog.cpp a46cff5e5dd425e3dbdd15632abfd5829f5562b4 | F src/SettingsDialog.cpp a46cff5e5dd425e3dbdd15632abfd5829f5562b4 | ||||||
| F src/SettingsDialog.h 4e2790f581e991c744ae9f86580f1972b8c7ff43 | F src/SettingsDialog.h 4e2790f581e991c744ae9f86580f1972b8c7ff43 | ||||||
| F src/Utils.cpp 9aff456712e4276b49083426301b3b96d3819c77 | F src/Utils.cpp 9aff456712e4276b49083426301b3b96d3819c77 | ||||||
| F src/Utils.h c546e478a1225a28c99cd4c30f70cf9be9804a2a | F src/Utils.h c546e478a1225a28c99cd4c30f70cf9be9804a2a | ||||||
| F src/main.cpp 0bba433f16072096cba1d48733b4e801df144800 | F src/main.cpp 2ac8badc2a63fa123ceae53382ce24cfe1b5a54b | ||||||
| F tools/git-push.sh 62cc58434cae5b7bcd6bd9d4cce8b08739f31cd7 x | F tools/git-push.sh 62cc58434cae5b7bcd6bd9d4cce8b08739f31cd7 x | ||||||
| F tools/pack.sh d7f38a498c4e9327fecd6a6e5ac27be270d43008 x | F tools/pack.sh d7f38a498c4e9327fecd6a6e5ac27be270d43008 x | ||||||
| F ui/BrowserWidget.ui 5ad98b13773afadb20a1a2c22148aaebe5dbd95d | F ui/BrowserWidget.ui 5ad98b13773afadb20a1a2c22148aaebe5dbd95d | ||||||
| @@ -213,10 +215,7 @@ F ui/CommitDialog.ui 6200f6cabdcf40a20812e811be28e0793f82516f | |||||||
| F ui/FileActionDialog.ui 89bb4dc2d0b8adcd41adcb11ec65f2028a09a12d | F ui/FileActionDialog.ui 89bb4dc2d0b8adcd41adcb11ec65f2028a09a12d | ||||||
| F ui/MainWindow.ui 8677f5c8bca5bf7561d5f64bfdd0cef5157c6ac7 | F ui/MainWindow.ui 8677f5c8bca5bf7561d5f64bfdd0cef5157c6ac7 | ||||||
| F ui/SettingsDialog.ui 2b7c2870e0054b0f4106f495d85d02c0b814df8b | F ui/SettingsDialog.ui 2b7c2870e0054b0f4106f495d85d02c0b814df8b | ||||||
| P 6b51d631f61ea685cf4ce84b3c34954dcd6338e2 | P 7f876a0b9e2c3c802938bd843e3e387e5e7e027a | ||||||
| R 7cb8f99d09af03a8c7fc0a6cb6e77784 | R 5d10ed53db083d8513096d001d39f7ff | ||||||
| T *branch * refactor |  | ||||||
| T *sym-refactor * |  | ||||||
| T -sym-trunk * |  | ||||||
| U kostas | U kostas | ||||||
| Z 7368bbf2e485a2aa190b88109453d953 | Z 36c407da296e8989c57827d80d13d2da | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| 7f876a0b9e2c3c802938bd843e3e387e5e7e027a | 7a4ea959c64034b6e20dec41a4a8c16a09397bfa | ||||||
							
								
								
									
										453
									
								
								src/Bridge.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										453
									
								
								src/Bridge.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,453 @@ | |||||||
|  | #include "Bridge.h" | ||||||
|  | #include <QStringList> | ||||||
|  | #include <QCoreApplication> | ||||||
|  | #include <LoggedProcess.h> | ||||||
|  | #include <QTextCodec> | ||||||
|  | #include <QDebug> | ||||||
|  | #include <QMessageBox> | ||||||
|  | #include <QDir> | ||||||
|  | #include <QTemporaryFile> | ||||||
|  |  | ||||||
|  | static const unsigned char		UTF8_BOM[] = { 0xEF, 0xBB, 0xBF }; | ||||||
|  |  | ||||||
|  | #include "Utils.h" | ||||||
|  |  | ||||||
|  | Bridge::RepoStatus Bridge::getRepoStatus() | ||||||
|  | { | ||||||
|  | 	QStringList res; | ||||||
|  | 	int exit_code = EXIT_FAILURE; | ||||||
|  |  | ||||||
|  | 	// We need to determine the reason why fossil has failed | ||||||
|  | 	// so we delay processing of the exit_code | ||||||
|  | 	if(!runFossilRaw(QStringList() << "info", &res, &exit_code, RUNFLAGS_SILENT_ALL)) | ||||||
|  | 		return REPO_NOT_FOUND; | ||||||
|  |  | ||||||
|  | 	bool run_ok = exit_code == EXIT_SUCCESS; | ||||||
|  |  | ||||||
|  | 	for(QStringList::iterator it=res.begin(); it!=res.end(); ++it) | ||||||
|  | 	{ | ||||||
|  | 		int col_index = it->indexOf(':'); | ||||||
|  | 		if(col_index==-1) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		QString key = it->left(col_index).trimmed(); | ||||||
|  | 		QString value = it->mid(col_index+1).trimmed(); | ||||||
|  |  | ||||||
|  | 		if(key=="fossil") | ||||||
|  | 		{ | ||||||
|  | 			if(value=="incorrect repository schema version") | ||||||
|  | 				return REPO_OLD_SCHEMA; | ||||||
|  | 			else if(value=="not within an open checkout") | ||||||
|  | 				return REPO_NOT_FOUND; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if(run_ok) | ||||||
|  | 		{ | ||||||
|  | 			if(key=="project-name") | ||||||
|  | 				projectName = value; | ||||||
|  | 			else if(key=="repository") | ||||||
|  | 				repositoryFile = value; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return run_ok ? REPO_OK : REPO_NOT_FOUND; | ||||||
|  | } | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | static QString ParseFossilQuery(QString line) | ||||||
|  | { | ||||||
|  | 	// Extract question | ||||||
|  | 	int qend = line.lastIndexOf('('); | ||||||
|  | 	if(qend == -1) | ||||||
|  | 		qend = line.lastIndexOf('['); | ||||||
|  | 	Q_ASSERT(qend!=-1); | ||||||
|  | 	line = line.left(qend); | ||||||
|  | 	line = line.trimmed(); | ||||||
|  | 	line += "?"; | ||||||
|  | 	line[0]=QString(line[0]).toUpper()[0]; | ||||||
|  | 	return line; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | bool Bridge::runFossil(const QStringList &args, QStringList *output, int runFlags) | ||||||
|  | { | ||||||
|  | 	int exit_code = EXIT_FAILURE; | ||||||
|  | 	if(!runFossilRaw(args, output, &exit_code, runFlags)) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	return exit_code == EXIT_SUCCESS; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | // Run fossil. Returns true if execution was successful regardless if fossil | ||||||
|  | // issued an error | ||||||
|  | bool Bridge::runFossilRaw(const QStringList &args, QStringList *output, int *exitCode, int runFlags) | ||||||
|  | { | ||||||
|  | 	bool silent_input = (runFlags & RUNFLAGS_SILENT_INPUT) != 0; | ||||||
|  | 	bool silent_output = (runFlags & RUNFLAGS_SILENT_OUTPUT) != 0; | ||||||
|  | 	bool detached = (runFlags & RUNFLAGS_DETACHED) != 0; | ||||||
|  |  | ||||||
|  | 	if(!silent_input) | ||||||
|  | 	{ | ||||||
|  | 		QString params; | ||||||
|  | 		foreach(QString p, args) | ||||||
|  | 		{ | ||||||
|  | 			if(p.indexOf(' ')!=-1) | ||||||
|  | 				params += '"' + p + "\" "; | ||||||
|  | 			else | ||||||
|  | 				params += p + ' '; | ||||||
|  | 		} | ||||||
|  | 		log("<b>> fossil "+params+"</b><br>", true); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	QString wkdir = getCurrentWorkspace(); | ||||||
|  |  | ||||||
|  | 	QString fossil = getFossilPath(); | ||||||
|  |  | ||||||
|  | 	// Detached processes use the command-line only, to avoid having to wait | ||||||
|  | 	// for the temporary args file to be released before returing | ||||||
|  | 	if(detached) | ||||||
|  | 		return QProcess::startDetached(fossil, args, wkdir); | ||||||
|  |  | ||||||
|  | 	// Make StatusBar message | ||||||
|  | #if 0 // FIXME | ||||||
|  | 	QString status_msg = tr("Running Fossil"); | ||||||
|  | 	if(args.length() > 0) | ||||||
|  | 		status_msg = QString("Fossil %0").arg(args[0].toCaseFolded()); | ||||||
|  | 	ScopedStatus status(status_msg, ui, progressBar); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	// Generate args file | ||||||
|  | 	const QStringList *final_args = &args; | ||||||
|  | 	QTemporaryFile args_file; | ||||||
|  | 	if(!args_file.open()) | ||||||
|  | 	{ | ||||||
|  | 		log(tr("Could not generate command line file")); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Write BOM | ||||||
|  | 	args_file.write(reinterpret_cast<const char *>(UTF8_BOM), sizeof(UTF8_BOM)); | ||||||
|  |  | ||||||
|  | 	// Write Args | ||||||
|  | 	foreach(const QString &arg, args) | ||||||
|  | 	{ | ||||||
|  | 		args_file.write(arg.toUtf8()); | ||||||
|  | 		args_file.write("\n"); | ||||||
|  | 	} | ||||||
|  | 	args_file.close(); | ||||||
|  |  | ||||||
|  | 	// Replace args with args filename | ||||||
|  | 	QStringList run_args; | ||||||
|  | 	run_args.append("--args"); | ||||||
|  | 	run_args.append(args_file.fileName()); | ||||||
|  | 	final_args = &run_args; | ||||||
|  |  | ||||||
|  | 	// Create fossil process | ||||||
|  | 	LoggedProcess process(parentWidget); | ||||||
|  | 	process.setWorkingDirectory(wkdir); | ||||||
|  |  | ||||||
|  | 	process.start(fossil, *final_args); | ||||||
|  | 	if(!process.waitForStarted()) | ||||||
|  | 	{ | ||||||
|  | 		log(tr("Could not start Fossil executable '%0'").arg(fossil)+"\n"); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	const QChar EOL_MARK('\n'); | ||||||
|  | 	QString ans_yes = 'y' + EOL_MARK; | ||||||
|  | 	QString ans_no = 'n' + EOL_MARK; | ||||||
|  | 	QString ans_always = 'a' + EOL_MARK; | ||||||
|  | 	QString ans_convert = 'c' + EOL_MARK; | ||||||
|  |  | ||||||
|  | 	abortOperation = false; | ||||||
|  | 	QString buffer; | ||||||
|  |  | ||||||
|  | #ifdef Q_OS_WIN | ||||||
|  | 	QTextCodec *codec = QTextCodec::codecForName("UTF-8"); | ||||||
|  | #else | ||||||
|  | 	QTextCodec *codec = QTextCodec::codecForLocale(); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	Q_ASSERT(codec); | ||||||
|  | 	QTextDecoder *decoder = codec->makeDecoder(); | ||||||
|  | 	Q_ASSERT(decoder); | ||||||
|  |  | ||||||
|  | 	while(true) | ||||||
|  | 	{ | ||||||
|  | 		QProcess::ProcessState state = process.state(); | ||||||
|  | 		qint64 bytes_avail = process.logBytesAvailable(); | ||||||
|  |  | ||||||
|  | 		if(state!=QProcess::Running && bytes_avail<1) | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 		if(abortOperation) | ||||||
|  | 		{ | ||||||
|  | 			log("\n* "+tr("Terminated")+" *\n"); | ||||||
|  | 			#ifdef Q_OS_WIN		// Verify this is still true on Qt5 | ||||||
|  | 				process.kill(); // QT on windows cannot terminate console processes with QProcess::terminate | ||||||
|  | 			#else | ||||||
|  | 				process.terminate(); | ||||||
|  | 			#endif | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		QByteArray input; | ||||||
|  | 		process.getLogAndClear(input); | ||||||
|  |  | ||||||
|  | 		#ifdef QT_DEBUG // Log fossil output in debug builds | ||||||
|  | 		if(!input.isEmpty()) | ||||||
|  | 			qDebug() << input; | ||||||
|  | 		#endif | ||||||
|  |  | ||||||
|  | 		buffer += decoder->toUnicode(input); | ||||||
|  |  | ||||||
|  | 		QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); | ||||||
|  |  | ||||||
|  | 		if(buffer.isEmpty()) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		// Normalize line endings | ||||||
|  | 		buffer = buffer.replace("\r\n", "\n"); | ||||||
|  | 		buffer = buffer.replace("\r", "\n"); | ||||||
|  |  | ||||||
|  | 		// Extract the last line | ||||||
|  | 		int last_line_start = buffer.lastIndexOf(EOL_MARK); | ||||||
|  |  | ||||||
|  | 		QString last_line; | ||||||
|  | 		QString before_last_line; | ||||||
|  | 		if(last_line_start != -1) | ||||||
|  | 		{ | ||||||
|  | 			last_line = buffer.mid(last_line_start+1); // Including the EOL | ||||||
|  |  | ||||||
|  | 			// Detect previous line | ||||||
|  | 			if(last_line_start>0) | ||||||
|  | 			{ | ||||||
|  | 				int before_last_line_start = buffer.lastIndexOf(EOL_MARK, last_line_start-1); | ||||||
|  | 				// No line before ? | ||||||
|  | 				if(before_last_line_start==-1) | ||||||
|  | 					before_last_line_start = 0; // Use entire line | ||||||
|  |  | ||||||
|  | 				// Extract previous line | ||||||
|  | 				before_last_line = buffer.mid(before_last_line_start, last_line_start-before_last_line_start); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 			last_line = buffer; | ||||||
|  |  | ||||||
|  | 		last_line = last_line.trimmed(); | ||||||
|  |  | ||||||
|  | 		// Check if we have a query | ||||||
|  | 		bool ends_qmark = !last_line.isEmpty() && last_line[last_line.length()-1]=='?'; | ||||||
|  | 		bool have_yn_query = last_line.toLower().indexOf("y/n")!=-1; | ||||||
|  | 		bool have_yna_query = last_line.toLower().indexOf("a=always/y/n")!=-1 || last_line.toLower().indexOf("yes/no/all")!=-1 || last_line.toLower().indexOf("a=all/y/n")!=-1; | ||||||
|  | 		bool have_an_query = last_line.toLower().indexOf("a=always/n")!=-1; | ||||||
|  | 		bool have_acyn_query = last_line.toLower().indexOf("a=all/c=convert/y/n")!=-1; | ||||||
|  |  | ||||||
|  | 		bool have_query = ends_qmark && (have_yn_query || have_yna_query || have_an_query || have_acyn_query); | ||||||
|  |  | ||||||
|  | 		// Flush all complete lines to the log and output | ||||||
|  | 		QStringList log_lines = buffer.left(last_line_start).split(EOL_MARK); | ||||||
|  | 		for(int l=0; l<log_lines.length(); ++l) | ||||||
|  | 		{ | ||||||
|  | 			// Do not output the last line if it not complete | ||||||
|  | 			if(l==log_lines.length()-1 && buffer[buffer.length()-1] != EOL_MARK ) | ||||||
|  | 				continue; | ||||||
|  |  | ||||||
|  | 			QString line = log_lines[l].trimmed(); | ||||||
|  |  | ||||||
|  | 			if(line.isEmpty()) | ||||||
|  | 				continue; | ||||||
|  |  | ||||||
|  | 			if(output) | ||||||
|  | 				output->append(line); | ||||||
|  |  | ||||||
|  | 			if(!silent_output) | ||||||
|  | 				log(line+"\n"); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Remove everything we processed (including the EOL) | ||||||
|  | 		buffer = buffer.mid(last_line_start+1) ; | ||||||
|  |  | ||||||
|  | 		// Now process any query | ||||||
|  | 		if(have_query && (have_yna_query || have_acyn_query)) | ||||||
|  | 		{ | ||||||
|  | 			log(last_line); | ||||||
|  | 			QString query = ParseFossilQuery(last_line); | ||||||
|  | 			QMessageBox::StandardButtons buttons = QMessageBox::YesToAll|QMessageBox::Yes|QMessageBox::No; | ||||||
|  |  | ||||||
|  | 			// Add any extra text available to the query | ||||||
|  | 			before_last_line = before_last_line.trimmed(); | ||||||
|  | 			if(!before_last_line.isEmpty()) | ||||||
|  | 				query = before_last_line + "\n" + query; | ||||||
|  |  | ||||||
|  | 			// Map the Convert option to the Apply button | ||||||
|  | 			if(have_acyn_query) | ||||||
|  | 				buttons |= QMessageBox::Apply; | ||||||
|  |  | ||||||
|  | 			QMessageBox::StandardButton res = DialogQuery(parentWidget, "Fossil", query, buttons); | ||||||
|  | 			if(res==QMessageBox::Yes) | ||||||
|  | 			{ | ||||||
|  | 				process.write(ans_yes.toLatin1()); | ||||||
|  | 				log("Y\n"); | ||||||
|  | 			} | ||||||
|  | 			else if(res==QMessageBox::YesAll) | ||||||
|  | 			{ | ||||||
|  | 				process.write(ans_always.toLatin1()); | ||||||
|  | 				log("A\n"); | ||||||
|  | 			} | ||||||
|  | 			else if(res==QMessageBox::Apply) | ||||||
|  | 			{ | ||||||
|  | 				process.write(ans_convert.toLatin1()); | ||||||
|  | 				log("C\n"); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				process.write(ans_no.toLatin1()); | ||||||
|  | 				log("N\n"); | ||||||
|  | 			} | ||||||
|  | 			buffer.clear(); | ||||||
|  | 		} | ||||||
|  | 		else if(have_query && have_yn_query) | ||||||
|  | 		{ | ||||||
|  | 			log(last_line); | ||||||
|  | 			QString query = ParseFossilQuery(last_line); | ||||||
|  | 			QMessageBox::StandardButton res = DialogQuery(parentWidget, "Fossil", query); | ||||||
|  |  | ||||||
|  | 			if(res==QMessageBox::Yes) | ||||||
|  | 			{ | ||||||
|  | 				process.write(ans_yes.toLatin1()); | ||||||
|  | 				log("Y\n"); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				process.write(ans_no.toLatin1()); | ||||||
|  | 				log("N\n"); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			buffer.clear(); | ||||||
|  | 		} | ||||||
|  | 		else if(have_query && have_an_query) | ||||||
|  | 		{ | ||||||
|  | 			log(last_line); | ||||||
|  | 			QString query = ParseFossilQuery(last_line); | ||||||
|  | 			QMessageBox::StandardButton res = DialogQuery(parentWidget, "Fossil", query, QMessageBox::YesToAll|QMessageBox::No); | ||||||
|  | 			if(res==QMessageBox::YesAll) | ||||||
|  | 			{ | ||||||
|  | 				process.write(ans_always.toLatin1()); | ||||||
|  | 				log("A\n"); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				process.write(ans_no.toLatin1()); | ||||||
|  | 				log("N\n"); | ||||||
|  | 			} | ||||||
|  | 			buffer.clear(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	delete decoder; | ||||||
|  |  | ||||||
|  | 	// Must be finished by now | ||||||
|  | 	Q_ASSERT(process.state()==QProcess::NotRunning); | ||||||
|  |  | ||||||
|  | 	QProcess::ExitStatus es = process.exitStatus(); | ||||||
|  |  | ||||||
|  | 	if(es!=QProcess::NormalExit) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	if(exitCode) | ||||||
|  | 		*exitCode = process.exitCode(); | ||||||
|  |  | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString Bridge::getFossilPath() | ||||||
|  | { | ||||||
|  | 	// Use the user-specified fossil if available | ||||||
|  | 	QString fossil_path = fossilPath; | ||||||
|  | 	if(!fossil_path.isEmpty()) | ||||||
|  | 		return QDir::toNativeSeparators(fossil_path); | ||||||
|  |  | ||||||
|  | 	QString fossil_exe = "fossil"; | ||||||
|  | #ifdef Q_OS_WIN | ||||||
|  | 	fossil_exe += ".exe"; | ||||||
|  | #endif | ||||||
|  | 	// Use our fossil if available | ||||||
|  | 	QString fuel_fossil = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + QDir::separator() + fossil_exe); | ||||||
|  |  | ||||||
|  | 	if(QFile::exists(fuel_fossil)) | ||||||
|  | 		return fuel_fossil; | ||||||
|  |  | ||||||
|  | 	// Otherwise assume there is a "fossil" executable in the path | ||||||
|  | 	return fossil_exe; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #define FOSSIL_CHECKOUT1	"_FOSSIL_" | ||||||
|  | #define FOSSIL_CHECKOUT2	".fslckout" | ||||||
|  | #define FOSSIL_EXT			"fossil" | ||||||
|  | #define PATH_SEP			"/" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool Bridge::isWorkspace(const QString &path) | ||||||
|  | { | ||||||
|  | 	if(path.length()==0) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	QFileInfo fi(path); | ||||||
|  | 	QString wkspace = path; | ||||||
|  | 	wkspace = fi.absoluteDir().absolutePath(); | ||||||
|  | 	QString checkout_file1 = wkspace + PATH_SEP + FOSSIL_CHECKOUT1; | ||||||
|  | 	QString checkout_file2 = wkspace + PATH_SEP + FOSSIL_CHECKOUT2; | ||||||
|  |  | ||||||
|  | 	return (QFileInfo(checkout_file1).exists() || QFileInfo(checkout_file2).exists()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | bool Bridge::uiRunning() const | ||||||
|  | { | ||||||
|  | 	return fossilUI.state() == QProcess::Running; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | bool Bridge::startUI(const QString &httpPort) | ||||||
|  | { | ||||||
|  | 	if(uiRunning()) | ||||||
|  | 	{ | ||||||
|  | 		log(tr("Fossil UI is already running")+"\n"); | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	fossilUI.setParent(parentWidget); | ||||||
|  | 	fossilUI.setProcessChannelMode(QProcess::MergedChannels); | ||||||
|  | 	fossilUI.setWorkingDirectory(getCurrentWorkspace()); | ||||||
|  |  | ||||||
|  | 	log("<b>> fossil ui</b><br>", true); | ||||||
|  | 	log(tr("Starting Fossil browser UI. Please wait.")+"\n"); | ||||||
|  | 	QString fossil = getFossilPath(); | ||||||
|  |  | ||||||
|  | 	fossilUI.start(fossil, QStringList() << "server" << "--localauth" << "-P" << httpPort ); | ||||||
|  |  | ||||||
|  | 	if(!fossilUI.waitForStarted() || fossilUI.state()!=QProcess::Running) | ||||||
|  | 	{ | ||||||
|  | 		log(tr("Could not start Fossil executable '%s'").arg(fossil)+"\n"); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | void Bridge::stopUI() | ||||||
|  | { | ||||||
|  | 	if(uiRunning()) | ||||||
|  | 	{ | ||||||
|  | #ifdef Q_WS_WIN | ||||||
|  | 		fossilUI.kill(); // QT on windows cannot terminate console processes with QProcess::terminate | ||||||
|  | #else | ||||||
|  | 		fossilUI.terminate(); | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  | 	fossilUI.close(); | ||||||
|  | } | ||||||
							
								
								
									
										93
									
								
								src/Bridge.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/Bridge.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | #ifndef BRIDGE_H | ||||||
|  | #define BRIDGE_H | ||||||
|  |  | ||||||
|  | class QStringList; | ||||||
|  | #include <QString> | ||||||
|  | #include <QObject> | ||||||
|  | #include <QProcess> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Bridge : public QObject | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	Bridge() | ||||||
|  | 	: QObject(0) | ||||||
|  | 	, parentWidget(0) | ||||||
|  | 	, abortOperation(false) | ||||||
|  | 	, logCallbackObject(0) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	bool runFossil(const QStringList &args, QStringList *output, int runFlags); | ||||||
|  | 	bool runFossilRaw(const QStringList &args, QStringList *output, int *exitCode, int runFlags); | ||||||
|  |  | ||||||
|  | 	enum RunFlags | ||||||
|  | 	{ | ||||||
|  | 		RUNFLAGS_NONE			= 0<<0, | ||||||
|  | 		RUNFLAGS_SILENT_INPUT	= 1<<0, | ||||||
|  | 		RUNFLAGS_SILENT_OUTPUT	= 1<<1, | ||||||
|  | 		RUNFLAGS_SILENT_ALL		= RUNFLAGS_SILENT_INPUT | RUNFLAGS_SILENT_OUTPUT, | ||||||
|  | 		RUNFLAGS_DETACHED		= 1<<2 | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	typedef void(*log_callback_t)(const QString &text, bool isHTML, QObject *object); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	void Init(QWidget *parent, log_callback_t callback, QObject *callbackObject, const QString &fossPath, const QString &workspace) | ||||||
|  | 	{ | ||||||
|  | 		parentWidget = parent; | ||||||
|  | 		logCallback = callback; | ||||||
|  | 		logCallbackObject = callbackObject; | ||||||
|  |  | ||||||
|  | 		fossilPath = fossPath; | ||||||
|  | 		currentWorkspace = workspace; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	static bool isWorkspace(const QString &path); | ||||||
|  | 	enum RepoStatus | ||||||
|  | 	{ | ||||||
|  | 		REPO_OK, | ||||||
|  | 		REPO_NOT_FOUND, | ||||||
|  | 		REPO_OLD_SCHEMA | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	RepoStatus getRepoStatus(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	bool uiRunning() const; | ||||||
|  | 	bool startUI(const QString &httpPort); | ||||||
|  | 	void stopUI(); | ||||||
|  |  | ||||||
|  | 	QString projectName; | ||||||
|  | 	QString repositoryFile; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	void log(const QString &text, bool isHTML=false) | ||||||
|  | 	{ | ||||||
|  | 		if(logCallback) | ||||||
|  | 			(*logCallback)(text, isHTML, logCallbackObject); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const QString &getCurrentWorkspace() | ||||||
|  | 	{ | ||||||
|  | 		return currentWorkspace; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	QString getFossilPath(); | ||||||
|  |  | ||||||
|  | 	QWidget				*parentWidget;	// fixme | ||||||
|  | 	bool				abortOperation;	// FIXME: No GUI for it yet | ||||||
|  |  | ||||||
|  | 	log_callback_t		logCallback; | ||||||
|  | 	QObject				*logCallbackObject; | ||||||
|  | 	QString				currentWorkspace; | ||||||
|  | 	QString				fossilPath;		// The value from the settings | ||||||
|  |  | ||||||
|  | 	QProcess			fossilUI; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif // BRIDGE_H | ||||||
| @@ -34,6 +34,7 @@ static const unsigned char		UTF8_BOM[] = { 0xEF, 0xBB, 0xBF }; | |||||||
| // 19: [5c46757d4b9765] on 2012-04-22 04:41:15 | // 19: [5c46757d4b9765] on 2012-04-22 04:41:15 | ||||||
| static const QRegExp			REGEX_STASH("\\s*(\\d+):\\s+\\[(.*)\\] on (\\d+)-(\\d+)-(\\d+) (\\d+):(\\d+):(\\d+)", Qt::CaseInsensitive); | static const QRegExp			REGEX_STASH("\\s*(\\d+):\\s+\\[(.*)\\] on (\\d+)-(\\d+)-(\\d+) (\\d+):(\\d+):(\\d+)", Qt::CaseInsensitive); | ||||||
|  |  | ||||||
|  | //#define BRIDGE_DISABLED | ||||||
|  |  | ||||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||||
| enum | enum | ||||||
| @@ -235,6 +236,8 @@ MainWindow::MainWindow(Settings &_settings, QWidget *parent, QString *workspaceP | |||||||
|  |  | ||||||
| 	applySettings(); | 	applySettings(); | ||||||
|  |  | ||||||
|  | 	bridge.Init(this, 0, 0, "", ""); | ||||||
|  |  | ||||||
| 	// Apply any explicit workspace path if available | 	// Apply any explicit workspace path if available | ||||||
| 	if(workspacePath && !workspacePath->isEmpty()) | 	if(workspacePath && !workspacePath->isEmpty()) | ||||||
| 		openWorkspace(*workspacePath); | 		openWorkspace(*workspacePath); | ||||||
| @@ -980,6 +983,7 @@ void MainWindow::updateFileView() | |||||||
| } | } | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
|  | #ifdef BRIDGE_DISABLED | ||||||
| MainWindow::RepoStatus MainWindow::getRepoStatus() | MainWindow::RepoStatus MainWindow::getRepoStatus() | ||||||
| { | { | ||||||
| 	QStringList res; | 	QStringList res; | ||||||
| @@ -1020,6 +1024,12 @@ MainWindow::RepoStatus MainWindow::getRepoStatus() | |||||||
|  |  | ||||||
| 	return run_ok ? REPO_OK : REPO_NOT_FOUND; | 	return run_ok ? REPO_OK : REPO_NOT_FOUND; | ||||||
| } | } | ||||||
|  | #else | ||||||
|  | MainWindow::RepoStatus MainWindow::getRepoStatus() | ||||||
|  | { | ||||||
|  | 	return (MainWindow::RepoStatus) bridge.getRepoStatus(); | ||||||
|  | } | ||||||
|  | #endif | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
| void MainWindow::updateStashView() | void MainWindow::updateStashView() | ||||||
| { | { | ||||||
| @@ -1064,6 +1074,8 @@ void MainWindow::on_actionClearLog_triggered() | |||||||
| 	ui->textBrowser->clear(); | 	ui->textBrowser->clear(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #ifdef BRIDGE_DISABLED | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
| bool MainWindow::runFossil(const QStringList &args, QStringList *output, int runFlags) | bool MainWindow::runFossil(const QStringList &args, QStringList *output, int runFlags) | ||||||
| { | { | ||||||
| @@ -1391,6 +1403,21 @@ QString MainWindow::getFossilPath() | |||||||
| 	// Otherwise assume there is a "fossil" executable in the path | 	// Otherwise assume there is a "fossil" executable in the path | ||||||
| 	return fossil_exe; | 	return fossil_exe; | ||||||
| } | } | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | bool MainWindow::runFossil(const QStringList &args, QStringList *output, int runFlags) | ||||||
|  | { | ||||||
|  | 	return bridge.runFossil(args, output, runFlags); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int *exitCode, int runFlags) | ||||||
|  | { | ||||||
|  | 	return bridge.runFossilRaw(args, output, exitCode, runFlags); | ||||||
|  |  | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
| void MainWindow::applySettings() | void MainWindow::applySettings() | ||||||
| { | { | ||||||
| @@ -1695,6 +1722,7 @@ void MainWindow::on_actionDiff_triggered() | |||||||
| } | } | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
|  | #ifdef BRIDGE_DISABLED | ||||||
| bool MainWindow::startUI() | bool MainWindow::startUI() | ||||||
| { | { | ||||||
| 	if(uiRunning()) | 	if(uiRunning()) | ||||||
| @@ -1741,6 +1769,23 @@ void MainWindow::stopUI() | |||||||
|  |  | ||||||
| 	ui->actionFossilUI->setChecked(false); | 	ui->actionFossilUI->setChecked(false); | ||||||
| } | } | ||||||
|  | #else | ||||||
|  | bool MainWindow::startUI() | ||||||
|  | { | ||||||
|  | 	QString port = settings.GetValue(FUEL_SETTING_HTTP_PORT).toString(); | ||||||
|  | 	bool started = bridge.startUI(port); | ||||||
|  | 	ui->actionFossilUI->setChecked(started); | ||||||
|  | 	return started; | ||||||
|  | } | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | void MainWindow::stopUI() | ||||||
|  | { | ||||||
|  | 	bridge.stopUI(); | ||||||
|  | 	ui->actionFossilUI->setChecked(false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
| void MainWindow::on_actionFossilUI_triggered() | void MainWindow::on_actionFossilUI_triggered() | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ | |||||||
| #include <QProcess> | #include <QProcess> | ||||||
| #include <QSet> | #include <QSet> | ||||||
| #include "SettingsDialog.h" | #include "SettingsDialog.h" | ||||||
|  | #include "Bridge.h" | ||||||
|  |  | ||||||
| namespace Ui { | namespace Ui { | ||||||
| 	class MainWindow; | 	class MainWindow; | ||||||
| @@ -261,6 +262,8 @@ private: | |||||||
| 	ViewMode			viewMode; | 	ViewMode			viewMode; | ||||||
| 	stringset_t			selectedDirs;	// The directory selected in the tree | 	stringset_t			selectedDirs;	// The directory selected in the tree | ||||||
|  |  | ||||||
|  | 	Bridge				bridge; | ||||||
|  |  | ||||||
| 	// Repository State | 	// Repository State | ||||||
| 	typedef QList<RepoFile*> filelist_t; | 	typedef QList<RepoFile*> filelist_t; | ||||||
| 	typedef QMap<QString, RepoFile*> filemap_t; | 	typedef QMap<QString, RepoFile*> filemap_t; | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ int main(int argc, char *argv[]) | |||||||
| { | { | ||||||
| 	QApplication app(argc, argv); | 	QApplication app(argc, argv); | ||||||
| 	app.setApplicationName("Fuel"); | 	app.setApplicationName("Fuel"); | ||||||
| 	app.setApplicationVersion("1.0.0"); | 	app.setApplicationVersion("2.0.0"); | ||||||
| 	app.setOrganizationDomain("fuel-scm.org"); | 	app.setOrganizationDomain("fuelscm.org"); | ||||||
| 	app.setOrganizationName("Fuel-SCM"); | 	app.setOrganizationName("Fuel-SCM"); | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user