mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	core: convert git_info to std::string
Quite a bit of fallout in users of this structure. Conveniently, since git-access.cpp is now C++ we can move some helpers from the monstrous qthelper.cpp to git-access.cpp. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
		
							parent
							
								
									ae299d5e66
								
							
						
					
					
						commit
						a123589efb
					
				
					 13 changed files with 290 additions and 319 deletions
				
			
		|  | @ -202,17 +202,18 @@ void CheckCloudConnection::gotContinent(QNetworkReply *reply) | |||
| extern "C" bool canReachCloudServer(struct git_info *info) | ||||
| { | ||||
| 	if (verbose) | ||||
| 		qWarning() << "Cloud storage: checking connection to cloud server" << info->url; | ||||
| 		qWarning() << "Cloud storage: checking connection to cloud server" << info->url.c_str(); | ||||
| 	bool connection = CheckCloudConnection().checkServer(); | ||||
| 	if (strstr(info->url, prefs.cloud_base_url) == nullptr) { | ||||
| 	if (info->url.find(prefs.cloud_base_url) == std::string::npos) { | ||||
| 		// we switched the cloud URL - likely because we couldn't reach the server passed in
 | ||||
| 		// the strstr with the offset is designed so we match the right component in the name;
 | ||||
| 		// the cloud_base_url ends with a '/', so we need the text starting at "git/..."
 | ||||
| 		char *newremote = format_string("%s%s", prefs.cloud_base_url, strstr(info->url, "org/git/") + 4); | ||||
| 		if (verbose) | ||||
| 			qDebug() << "updating remote to: " << newremote; | ||||
| 		free((void*)info->url); | ||||
| 		info->url = newremote; | ||||
| 		size_t pos = info->url.find("org/git/"); | ||||
| 		if (pos != std::string::npos) { | ||||
| 			info->url = format_string_std("%s%s", prefs.cloud_base_url, info->url.c_str() + pos + 4); | ||||
| 			if (verbose) | ||||
| 				qDebug() << "updating remote to: " << info->url.c_str(); | ||||
| 		} | ||||
| 	} | ||||
| 	return connection; | ||||
| } | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ | |||
| #include "dive.h" | ||||
| #include "divelog.h" | ||||
| #include "subsurface-string.h" | ||||
| #include "format.h" | ||||
| #include "errorhelper.h" | ||||
| #include "file.h" | ||||
| #include "git-access.h" | ||||
|  | @ -250,7 +251,7 @@ static int parse_file_buffer(const char *filename, std::string &mem, struct dive | |||
| 	return parse_xml_buffer(filename, mem.data(), mem.size(), log, NULL); | ||||
| } | ||||
| 
 | ||||
| extern "C" bool remote_repo_uptodate(const char *filename, struct git_info *info) | ||||
| bool remote_repo_uptodate(const char *filename, struct git_info *info) | ||||
| { | ||||
| 	std::string current_sha = saved_git_id; | ||||
| 
 | ||||
|  | @ -278,14 +279,11 @@ extern "C" int parse_file(const char *filename, struct divelog *log) | |||
| 			 * Opening the cloud storage repository failed for some reason | ||||
| 			 * give up here and don't send errors about git repositories | ||||
| 			 */ | ||||
| 			if (info.is_subsurface_cloud) { | ||||
| 				cleanup_git_info(&info); | ||||
| 			if (info.is_subsurface_cloud) | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		int ret = git_load_dives(&info, log); | ||||
| 		cleanup_git_info(&info); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,8 +17,12 @@ | |||
| #include <fcntl.h> | ||||
| #include <stdarg.h> | ||||
| #include <git2.h> | ||||
| #include <QString> | ||||
| #include <QRegularExpression> | ||||
| #include <QNetworkProxy> | ||||
| 
 | ||||
| #include "subsurface-string.h" | ||||
| #include "format.h" | ||||
| #include "membuffer.h" | ||||
| #include "strndup.h" | ||||
| #include "qthelper.h" | ||||
|  | @ -117,12 +121,20 @@ static int transfer_progress_cb(const git_transfer_progress *stats, void *) | |||
| // the initial push to sync the repos is mapped to 10% of overall progress
 | ||||
| static int push_transfer_progress_cb(unsigned int current, unsigned int total, size_t, void *) | ||||
| { | ||||
| 	char buf[80]; | ||||
| 	snprintf(buf, sizeof(buf), translate("gettextFromC", "Transfer to storage (%d/%d)"), current, total); | ||||
| 	return git_storage_update_progress(buf); | ||||
| 	std::string buf = casprintf_loc(translate("gettextFromC", "Transfer to storage (%d/%d)"), current, total); | ||||
| 	return git_storage_update_progress(buf.c_str()); | ||||
| } | ||||
| 
 | ||||
| extern "C" char *get_local_dir(const char *url, const char *branch) | ||||
| std::string normalize_cloud_name(const std::string &remote_in) | ||||
| { | ||||
| 	// replace ssrf-cloud-XX.subsurface... names with cloud.subsurface... names
 | ||||
| 	// that trailing '/' is to match old code
 | ||||
| 	QString ri = QString::fromStdString(remote_in); | ||||
| 	ri.replace(QRegularExpression(CLOUD_HOST_PATTERN), CLOUD_HOST_GENERIC "/"); | ||||
| 	return ri.toStdString(); | ||||
| } | ||||
| 
 | ||||
| std::string get_local_dir(const std::string &url, const std::string &branch) | ||||
| { | ||||
| 	SHA_CTX ctx; | ||||
| 	unsigned char hash[20]; | ||||
|  | @ -133,9 +145,6 @@ extern "C" char *get_local_dir(const char *url, const char *branch) | |||
| 	// which server to pick changed, or because the user is on a different continent),
 | ||||
| 	// then the hash and therefore the local directory would change. To prevent that
 | ||||
| 	// from happening, normalize the cloud string to always use the old default name.
 | ||||
| 	// That's trivial with QString operations and painful to do right in plain C, so
 | ||||
| 	// let's be lazy and call a C++ helper function
 | ||||
| 	// just remember to free the string we get back
 | ||||
| 	std::string remote = normalize_cloud_name(url); | ||||
| 
 | ||||
| 	// That zero-byte update is so that we don't get hash
 | ||||
|  | @ -143,19 +152,18 @@ extern "C" char *get_local_dir(const char *url, const char *branch) | |||
| 	SHA1_Init(&ctx); | ||||
| 	SHA1_Update(&ctx, remote.c_str(), remote.size()); | ||||
| 	SHA1_Update(&ctx, "", 1); | ||||
| 	SHA1_Update(&ctx, branch, strlen(branch)); | ||||
| 	SHA1_Update(&ctx, branch.c_str(), branch.size()); | ||||
| 	SHA1_Final(hash, &ctx); | ||||
| 	return format_string("%s/cloudstorage/%02x%02x%02x%02x%02x%02x%02x%02x", | ||||
| 	return format_string_std("%s/cloudstorage/%02x%02x%02x%02x%02x%02x%02x%02x", | ||||
| 			system_default_directory(), | ||||
| 			hash[0], hash[1], hash[2], hash[3], | ||||
| 			hash[4], hash[5], hash[6], hash[7]); | ||||
| } | ||||
| 
 | ||||
| static char *move_local_cache(struct git_info *info) | ||||
| static std::string move_local_cache(struct git_info *info) | ||||
| { | ||||
| 	char *old_path = get_local_dir(info->url, info->branch); | ||||
| 	char *new_path = move_away(old_path); | ||||
| 	free(old_path); | ||||
| 	std::string old_path = get_local_dir(info->url, info->branch); | ||||
| 	std::string new_path = move_away(old_path); | ||||
| 	return new_path; | ||||
| } | ||||
| 
 | ||||
|  | @ -248,15 +256,12 @@ extern "C" int credential_ssh_cb(git_cred **out, | |||
| 
 | ||||
| 	// TODO: We need a way to differentiate between password and private key authentication
 | ||||
| 	if (allowed_types & GIT_CREDTYPE_SSH_KEY) { | ||||
| 		char *priv_key = format_string("%s/%s", system_default_directory(), "ssrf_remote.key"); | ||||
| 		if (!access(priv_key, F_OK)) { | ||||
| 		std::string priv_key = std::string(system_default_directory()) + "/ssrf_remote.key"; | ||||
| 		if (!access(priv_key.c_str(), F_OK)) { | ||||
| 			if (exceeded_auth_attempts()) | ||||
| 				return GIT_EUSER; | ||||
| 			int ret = git_cred_ssh_key_new(out, username, NULL, priv_key, passphrase); | ||||
| 			free(priv_key); | ||||
| 			return ret; | ||||
| 			return git_cred_ssh_key_new(out, username, NULL, priv_key.c_str(), passphrase); | ||||
| 		} | ||||
| 		free(priv_key); | ||||
| 	} | ||||
| 
 | ||||
| 	if (allowed_types & GIT_CREDTYPE_USERPASS_PLAINTEXT) { | ||||
|  | @ -346,7 +351,7 @@ static int try_to_git_merge(struct git_info *info, git_reference **local_p, git_ | |||
| 	git_commit *local_commit, *remote_commit, *base_commit; | ||||
| 	git_index *merged_index; | ||||
| 	git_merge_options merge_options; | ||||
| 	struct membuffer msg = { 0, 0, NULL}; | ||||
| 	struct membufferpp msg; | ||||
| 
 | ||||
| 	if (verbose) { | ||||
| 		char outlocal[41], outremote[41]; | ||||
|  | @ -450,7 +455,6 @@ static int try_to_git_merge(struct git_info *info, git_reference **local_p, git_ | |||
| 		git_signature_free(author); | ||||
| 		if (verbose) | ||||
| 			report_info("git storage: successfully merged repositories"); | ||||
| 		free_buffer(&msg); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -458,7 +462,6 @@ diverged_error: | |||
| 	return report_error("%s", translate("gettextFromC", "Remote storage and local data diverged")); | ||||
| 
 | ||||
| write_error: | ||||
| 	free_buffer(&msg); | ||||
| 	return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: writing the data failed (%s)"), giterr_last()->message); | ||||
| } | ||||
| 
 | ||||
|  | @ -467,11 +470,10 @@ write_error: | |||
| // and ask them to retry the operation (which will then refresh the data from the cloud server)
 | ||||
| static int cleanup_local_cache(struct git_info *info) | ||||
| { | ||||
| 	char *backup_path = move_local_cache(info); | ||||
| 	report_info("git storage: problems with local cache, moved to %s", backup_path); | ||||
| 	std::string backup_path = move_local_cache(info); | ||||
| 	report_info("git storage: problems with local cache, moved to %s", backup_path.c_str()); | ||||
| 	report_error("%s", translate("gettextFromC", "Problems with local cache of Subsurface cloud data")); | ||||
| 	report_error(translate("gettextFromC", "Moved cache data to %s. Please try the operation again."), backup_path); | ||||
| 	free(backup_path); | ||||
| 	report_error(translate("gettextFromC", "Moved cache data to %s. Please try the operation again."), backup_path.c_str()); | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
|  | @ -576,17 +578,17 @@ static int check_remote_status(struct git_info *info, git_remote *origin) | |||
| 	if (verbose) | ||||
| 		report_info("git storage: check remote status\n"); | ||||
| 
 | ||||
| 	if (git_branch_lookup(&local_ref, info->repo, info->branch, GIT_BRANCH_LOCAL)) { | ||||
| 		report_info("git storage: branch %s is missing in local repo", info->branch); | ||||
| 	if (git_branch_lookup(&local_ref, info->repo, info->branch.c_str(), GIT_BRANCH_LOCAL)) { | ||||
| 		report_info("git storage: branch %s is missing in local repo", info->branch.c_str()); | ||||
| 		if (info->is_subsurface_cloud) | ||||
| 			return cleanup_local_cache(info); | ||||
| 		else | ||||
| 			return report_error("Git cache branch %s no longer exists", info->branch); | ||||
| 			return report_error("Git cache branch %s no longer exists", info->branch.c_str()); | ||||
| 	} | ||||
| 	if (git_branch_upstream(&remote_ref, local_ref)) { | ||||
| 		/* so there is no upstream branch for our branch; that's a problem.
 | ||||
| 		 * let's push our branch */ | ||||
| 		report_info("git storage: branch %s is missing in remote, pushing branch", info->branch); | ||||
| 		report_info("git storage: branch %s is missing in remote, pushing branch", info->branch.c_str()); | ||||
| 		git_strarray refspec; | ||||
| 		git_reference_list(&refspec, info->repo); | ||||
| 		git_push_options opts = GIT_PUSH_OPTIONS_INIT; | ||||
|  | @ -608,62 +610,69 @@ static int check_remote_status(struct git_info *info, git_remote *origin) | |||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| static std::string getProxyString() | ||||
| { | ||||
| 	if (prefs.proxy_type == QNetworkProxy::HttpProxy) { | ||||
| 		if (prefs.proxy_auth) | ||||
| 			return format_string_std("http://%s:%s@%s:%d", prefs.proxy_user, prefs.proxy_pass, | ||||
| 					prefs.proxy_host, prefs.proxy_port); | ||||
| 		else | ||||
| 			return format_string_std("http://%s:%d", prefs.proxy_host, prefs.proxy_port); | ||||
| 	} | ||||
| 	return std::string(); | ||||
| } | ||||
| 
 | ||||
| /* this is (so far) only used by the git storage tests to remove a remote branch
 | ||||
|  * it will print out errors, but not return an error (as this isn't a function that | ||||
|  * we test as part of the tests, it's a helper to not leave loads of dead branches on | ||||
|  * the server) | ||||
|  */ | ||||
| extern "C" void delete_remote_branch(git_repository *repo, const char *remote, const char *branch) | ||||
| void delete_remote_branch(git_repository *repo, const std::string &remote, const std::string &branch) | ||||
| { | ||||
| 	int error; | ||||
| 	char *proxy_string; | ||||
| 	git_remote *origin; | ||||
| 	git_config *conf; | ||||
| 
 | ||||
| 	/* set up the config and proxy information in order to connect to the server */ | ||||
| 	git_repository_config(&conf, repo); | ||||
| 	if (getProxyString(&proxy_string)) { | ||||
| 		git_config_set_string(conf, "http.proxy", proxy_string); | ||||
| 		free(proxy_string); | ||||
| 	std::string proxy_string = getProxyString(); | ||||
| 	if (!proxy_string.empty()) { | ||||
| 		git_config_set_string(conf, "http.proxy", proxy_string.c_str()); | ||||
| 	} else { | ||||
| 		git_config_delete_entry(conf, "http.proxy"); | ||||
| 	} | ||||
| 	if (git_remote_lookup(&origin, repo, "origin")) { | ||||
| 		report_info("git storage: repository '%s' origin lookup failed (%s)", remote, giterr_last() ? giterr_last()->message : "(unspecified)"); | ||||
| 		report_info("git storage: repository '%s' origin lookup failed (%s)", remote.c_str(), giterr_last() ? giterr_last()->message : "(unspecified)"); | ||||
| 		return; | ||||
| 	} | ||||
| 	/* fetch the remote state */ | ||||
| 	git_fetch_options f_opts = GIT_FETCH_OPTIONS_INIT; | ||||
| 	auth_attempt = 0; | ||||
| 	f_opts.callbacks.credentials = credential_https_cb; | ||||
| 	error = git_remote_fetch(origin, NULL, &f_opts, NULL); | ||||
| 	if (error) { | ||||
| 	if (git_remote_fetch(origin, NULL, &f_opts, NULL)) { | ||||
| 		report_info("git storage: remote fetch failed (%s)\n", giterr_last() ? giterr_last()->message : "authentication failed"); | ||||
| 		return; | ||||
| 	} | ||||
| 	/* delete the remote branch by pushing to ":refs/heads/<branch>" */ | ||||
| 	git_strarray refspec; | ||||
| 	char *branch_ref = format_string(":refs/heads/%s", branch); | ||||
| 	std::string branch_ref = std::string(":refs/heads/") + branch; | ||||
| 	char *dummy = branch_ref.data(); | ||||
| 	refspec.count = 1; | ||||
| 	refspec.strings = &branch_ref; | ||||
| 	refspec.strings = &dummy; | ||||
| 	git_push_options p_opts = GIT_PUSH_OPTIONS_INIT; | ||||
| 	auth_attempt = 0; | ||||
| 	p_opts.callbacks.credentials = credential_https_cb; | ||||
| 	error = git_remote_push(origin, &refspec, &p_opts); | ||||
| 	free(branch_ref); | ||||
| 	if (error) { | ||||
| 		report_info("git storage: unable to delete branch '%s'", branch); | ||||
| 	if (git_remote_push(origin, &refspec, &p_opts)) { | ||||
| 		report_info("git storage: unable to delete branch '%s'", branch.c_str()); | ||||
| 		report_info("git storage: error was (%s)\n", giterr_last() ? giterr_last()->message : "(unspecified)"); | ||||
| 	} | ||||
| 	git_remote_free(origin); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| extern "C" int sync_with_remote(struct git_info *info) | ||||
| int sync_with_remote(struct git_info *info) | ||||
| { | ||||
| 	int error; | ||||
| 	git_remote *origin; | ||||
| 	char *proxy_string; | ||||
| 	git_config *conf; | ||||
| 
 | ||||
| 	if (git_local_only) { | ||||
|  | @ -672,14 +681,14 @@ extern "C" int sync_with_remote(struct git_info *info) | |||
| 		return 0; | ||||
| 	} | ||||
| 	if (verbose) | ||||
| 		report_info("git storage: sync with remote %s[%s]\n", info->url, info->branch); | ||||
| 		report_info("git storage: sync with remote %s[%s]\n", info->url.c_str(), info->branch.c_str()); | ||||
| 	git_storage_update_progress(translate("gettextFromC", "Sync with cloud storage")); | ||||
| 	git_repository_config(&conf, info->repo); | ||||
| 	if (info->transport == RT_HTTPS && getProxyString(&proxy_string)) { | ||||
| 	std::string proxy_string = getProxyString(); | ||||
| 	if (info->transport == RT_HTTPS && !proxy_string.empty()) { | ||||
| 		if (verbose) | ||||
| 			report_info("git storage: set proxy to \"%s\"\n", proxy_string); | ||||
| 		git_config_set_string(conf, "http.proxy", proxy_string); | ||||
| 		free(proxy_string); | ||||
| 			report_info("git storage: set proxy to \"%s\"\n", proxy_string.c_str()); | ||||
| 		git_config_set_string(conf, "http.proxy", proxy_string.c_str()); | ||||
| 	} else { | ||||
| 		if (verbose) | ||||
| 			report_info("git storage: delete proxy setting\n"); | ||||
|  | @ -693,9 +702,9 @@ extern "C" int sync_with_remote(struct git_info *info) | |||
| 	error = git_remote_lookup(&origin, info->repo, "origin"); | ||||
| 	if (error) { | ||||
| 		const char *msg = giterr_last()->message; | ||||
| 		report_info("git storage: repo %s origin lookup failed with: %s", info->url, msg); | ||||
| 		report_info("git storage: repo %s origin lookup failed with: %s", info->url.c_str(), msg); | ||||
| 		if (!info->is_subsurface_cloud) | ||||
| 			report_error("Repository '%s' origin lookup failed (%s)", info->url, msg); | ||||
| 			report_error("Repository '%s' origin lookup failed (%s)", info->url.c_str(), msg); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -726,7 +735,7 @@ extern "C" int sync_with_remote(struct git_info *info) | |||
| 		if (info->is_subsurface_cloud) | ||||
| 			report_error("Cannot sync with cloud server, working with offline copy"); | ||||
| 		else | ||||
| 			report_error("Unable to fetch remote '%s'", info->url); | ||||
| 			report_error("Unable to fetch remote '%s'", info->url.c_str()); | ||||
| 		// If we returned GIT_EUSER during authentication, giterr_last() returns NULL
 | ||||
| 		report_info("git storage: remote fetch failed (%s)\n", giterr_last() ? giterr_last()->message : "authentication failed"); | ||||
| 		// Since we failed to sync with online repository, enter offline mode
 | ||||
|  | @ -748,18 +757,17 @@ static bool update_local_repo(struct git_info *info) | |||
| 	if (!git_repository_head(&head, info->repo)) { | ||||
| 		const char *name; | ||||
| 		if (!git_branch_name(&name, head)) { | ||||
| 			if (strcmp(name, info->branch)) { | ||||
| 				char *branchref = format_string("refs/heads/%s", info->branch); | ||||
| 				report_info("git storage: setting cache branch from '%s' to '%s'", name, info->branch); | ||||
| 				git_repository_set_head(info->repo, branchref); | ||||
| 				free(branchref); | ||||
| 			if (info->branch != name) { | ||||
| 				std::string branchref = "refs/heads/" + info->branch; | ||||
| 				report_info("git storage: setting cache branch from '%s' to '%s'", name, info->branch.c_str()); | ||||
| 				git_repository_set_head(info->repo, branchref.c_str()); | ||||
| 			} | ||||
| 		} | ||||
| 		git_reference_free(head); | ||||
| 	} | ||||
| 	/* make sure we have the correct origin - the cloud server URL could have changed */ | ||||
| 	if (git_remote_set_url(info->repo, "origin", info->url)) { | ||||
| 		report_info("git storage: failed to update origin to '%s'", info->url); | ||||
| 	if (git_remote_set_url(info->repo, "origin", info->url.c_str())) { | ||||
| 		report_info("git storage: failed to update origin to '%s'", info->url.c_str()); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -771,7 +779,6 @@ static bool update_local_repo(struct git_info *info) | |||
| 
 | ||||
| static int repository_create_cb(git_repository **out, const char *path, int bare, void *) | ||||
| { | ||||
| 	char *proxy_string; | ||||
| 	git_config *conf; | ||||
| 
 | ||||
| 	int ret = git_repository_init(out, path, bare); | ||||
|  | @ -782,11 +789,11 @@ static int repository_create_cb(git_repository **out, const char *path, int bare | |||
| 	} | ||||
| 
 | ||||
| 	git_repository_config(&conf, *out); | ||||
| 	if (getProxyString(&proxy_string)) { | ||||
| 	std::string proxy_string = getProxyString(); | ||||
| 	if (!proxy_string.empty()) { | ||||
| 		if (verbose) | ||||
| 			report_info("git storage: set proxy to \"%s\"\n", proxy_string); | ||||
| 		git_config_set_string(conf, "http.proxy", proxy_string); | ||||
| 		free(proxy_string); | ||||
| 			report_info("git storage: set proxy to \"%s\"\n", proxy_string.c_str()); | ||||
| 		git_config_set_string(conf, "http.proxy", proxy_string.c_str()); | ||||
| 	} else { | ||||
| 		if (verbose) | ||||
| 			report_info("git storage: delete proxy setting\n"); | ||||
|  | @ -800,34 +807,30 @@ static int repository_create_cb(git_repository **out, const char *path, int bare | |||
| static bool create_and_push_remote(struct git_info *info) | ||||
| { | ||||
| 	git_config *conf; | ||||
| 	char *variable_name, *head; | ||||
| 
 | ||||
| 	if (verbose) | ||||
| 		report_info("git storage: create and push remote\n"); | ||||
| 
 | ||||
| 	/* first make sure the directory for the local cache exists */ | ||||
| 	subsurface_mkdir(info->localdir); | ||||
| 	subsurface_mkdir(info->localdir.c_str()); | ||||
| 
 | ||||
| 	head = format_string("refs/heads/%s", info->branch); | ||||
| 	std::string head = "refs/heads/" + info->branch; | ||||
| 
 | ||||
| 	/* set up the origin to point to our remote */ | ||||
| 	git_repository_init_options init_opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; | ||||
| 	init_opts.origin_url = info->url; | ||||
| 	init_opts.initial_head = head; | ||||
| 	init_opts.origin_url = info->url.c_str(); | ||||
| 	init_opts.initial_head = head.c_str(); | ||||
| 
 | ||||
| 	/* now initialize the repository with */ | ||||
| 	git_repository_init_ext(&info->repo, info->localdir, &init_opts); | ||||
| 	git_repository_init_ext(&info->repo, info->localdir.c_str(), &init_opts); | ||||
| 
 | ||||
| 	/* create a config so we can set the remote tracking branch */ | ||||
| 	git_repository_config(&conf, info->repo); | ||||
| 	variable_name = format_string("branch.%s.remote", info->branch); | ||||
| 	git_config_set_string(conf, variable_name, "origin"); | ||||
| 	free(variable_name); | ||||
| 	std::string variable_name = "branch." + info->branch + ".remote"; | ||||
| 	git_config_set_string(conf, variable_name.c_str(), "origin"); | ||||
| 
 | ||||
| 	variable_name = format_string("branch.%s.merge", info->branch); | ||||
| 	git_config_set_string(conf, variable_name, head); | ||||
| 	free(head); | ||||
| 	free(variable_name); | ||||
| 	variable_name = "branch." + info->branch + ".merge"; | ||||
| 	git_config_set_string(conf, variable_name.c_str(), head.c_str()); | ||||
| 
 | ||||
| 	/* finally create an empty commit and push it to the remote */ | ||||
| 	if (do_git_save(info, false, true)) | ||||
|  | @ -853,18 +856,18 @@ static bool create_local_repo(struct git_info *info) | |||
| 	opts.repository_cb = repository_create_cb; | ||||
| 	opts.fetch_opts.callbacks.certificate_check = certificate_check_cb; | ||||
| 
 | ||||
| 	opts.checkout_branch = info->branch; | ||||
| 	opts.checkout_branch = info->branch.c_str(); | ||||
| 	if (info->is_subsurface_cloud && !canReachCloudServer(info)) { | ||||
| 		report_info("git storage: cannot reach remote server"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (verbose > 1) | ||||
| 		report_info("git storage: calling git_clone()\n"); | ||||
| 	error = git_clone(&info->repo, info->url, info->localdir, &opts); | ||||
| 	error = git_clone(&info->repo, info->url.c_str(), info->localdir.c_str(), &opts); | ||||
| 	if (verbose > 1) | ||||
| 		report_info("git storage: returned from git_clone() with return value %d\n", error); | ||||
| 	if (error) { | ||||
| 		report_info("git storage: clone of %s failed", info->url); | ||||
| 		report_info("git storage: clone of %s failed", info->url.c_str()); | ||||
| 		const char *msg = ""; | ||||
| 		if (giterr_last()) { | ||||
| 			 msg = giterr_last()->message; | ||||
|  | @ -872,9 +875,9 @@ static bool create_local_repo(struct git_info *info) | |||
| 		} else { | ||||
| 			 report_info("git storage: giterr_last() is null\n"); | ||||
| 		} | ||||
| 		char *pattern = format_string("reference 'refs/remotes/origin/%s' not found", info->branch); | ||||
| 		std::string pattern = format_string_std("reference 'refs/remotes/origin/%s' not found", info->branch.c_str()); | ||||
| 		// it seems that we sometimes get 'Reference' and sometimes 'reference'
 | ||||
| 		if (includes_string_caseinsensitive(msg, pattern)) { | ||||
| 		if (includes_string_caseinsensitive(msg, pattern.c_str())) { | ||||
| 			/* we're trying to open the remote branch that corresponds
 | ||||
| 			 * to our cloud storage and the branch doesn't exist. | ||||
| 			 * So we need to create the branch and push it to the remote */ | ||||
|  | @ -887,19 +890,18 @@ static bool create_local_repo(struct git_info *info) | |||
| 			report_error("%s", translate("gettextFromC", "Error connecting to Subsurface cloud storage")); | ||||
| #endif | ||||
| 		} else { | ||||
| 			report_error(translate("gettextFromC", "git clone of %s failed (%s)"), info->url, msg); | ||||
| 			report_error(translate("gettextFromC", "git clone of %s failed (%s)"), info->url.c_str(), msg); | ||||
| 		} | ||||
| 		free(pattern); | ||||
| 	} | ||||
| 	return !error; | ||||
| } | ||||
| 
 | ||||
| static enum remote_transport url_to_remote_transport(const char *remote) | ||||
| static enum remote_transport url_to_remote_transport(const std::string &remote) | ||||
| { | ||||
| 	/* figure out the remote transport */ | ||||
| 	if (strncmp(remote, "ssh://", 6) == 0) | ||||
| 	if (starts_with(remote, "ssh://")) | ||||
| 		return RT_SSH; | ||||
| 	else if (strncmp(remote, "https://", 8) == 0) | ||||
| 	else if (starts_with(remote.c_str(), "https://")) | ||||
| 		return RT_HTTPS; | ||||
| 	else | ||||
| 		return RT_OTHER; | ||||
|  | @ -910,24 +912,24 @@ static bool get_remote_repo(struct git_info *info) | |||
| 	struct stat st; | ||||
| 
 | ||||
| 	if (verbose > 1) { | ||||
| 		report_info("git storage: accessing %s\n", info->url); | ||||
| 		report_info("git storage: accessing %s\n", info->url.c_str()); | ||||
| 	} | ||||
| 	git_storage_update_progress(translate("gettextFromC", "Synchronising data file")); | ||||
| 	/* Do we already have a local cache? */ | ||||
| 	if (!subsurface_stat(info->localdir, &st)) { | ||||
| 	if (!subsurface_stat(info->localdir.c_str(), &st)) { | ||||
| 		int error; | ||||
| 
 | ||||
| 		if (verbose) | ||||
| 			report_info("git storage: update local repo\n"); | ||||
| 
 | ||||
| 		error = git_repository_open(&info->repo, info->localdir); | ||||
| 		error = git_repository_open(&info->repo, info->localdir.c_str()); | ||||
| 		if (error) { | ||||
| 			const char *msg = giterr_last()->message; | ||||
| 			report_info("git storage: unable to open local cache at %s: %s", info->localdir, msg); | ||||
| 			report_info("git storage: unable to open local cache at %s: %s", info->localdir.c_str(), msg); | ||||
| 			if (info->is_subsurface_cloud) | ||||
| 				(void)cleanup_local_cache(info); | ||||
| 			else | ||||
| 				report_error("Unable to open git cache repository at %s: %s", info->localdir, msg); | ||||
| 				report_error("Unable to open git cache repository at %s: %s", info->localdir.c_str(), msg); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -955,17 +957,17 @@ static bool get_remote_repo(struct git_info *info) | |||
|  * Remove the user name from the url if it exists, and | ||||
|  * save it in 'info->username'. | ||||
|  */ | ||||
| static void extract_username(struct git_info *info, char *url) | ||||
| std::string extract_username(struct git_info *info, const std::string &url) | ||||
| { | ||||
| 	char c; | ||||
| 	char *p = url; | ||||
| 	const char *p = url.c_str(); | ||||
| 
 | ||||
| 	while ((c = *p++) >= 'a' && c <= 'z') | ||||
| 		/* nothing */; | ||||
| 	if (c != ':') | ||||
| 		return; | ||||
| 		return url; | ||||
| 	if (*p++ != '/' || *p++ != '/') | ||||
| 		return; | ||||
| 		return url; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Ok, we found "[a-z]*://" and we think we have a real | ||||
|  | @ -974,38 +976,38 @@ static void extract_username(struct git_info *info, char *url) | |||
| 	 */ | ||||
| 	info->transport = url_to_remote_transport(url); | ||||
| 
 | ||||
| 	char *at = strchr(p, '@'); | ||||
| 	const char *at = strchr(p, '@'); | ||||
| 	if (!at) | ||||
| 		return; | ||||
| 		return url; | ||||
| 
 | ||||
| 	/* was this the @ that denotes an account? that means it was before the
 | ||||
| 	 * first '/' after the protocol:// - so let's find a '/' after that and compare */
 | ||||
| 	char *slash = strchr(p, '/'); | ||||
| 	const char *slash = strchr(p, '/'); | ||||
| 	if (!slash || at > slash) | ||||
| 		return; | ||||
| 		return url; | ||||
| 
 | ||||
| 	/* grab the part between "protocol://" and "@" as encoded email address
 | ||||
| 	 * (that's our username) and move the rest of the URL forward, remembering | ||||
| 	 * to copy the closing NUL as well */ | ||||
| 	info->username = strndup(p, at - p); | ||||
| 	memmove(p, at + 1, strlen(at + 1) + 1); | ||||
| 	info->username = std::string(p, at - p); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Ugly, ugly. Parsing the remote repo user name also sets | ||||
| 	 * it in the preferences. We should do this somewhere else! | ||||
| 	 */ | ||||
| 	prefs.cloud_storage_email_encoded = strdup(info->username); | ||||
| 	prefs.cloud_storage_email_encoded = strdup(info->username.c_str()); | ||||
| 
 | ||||
| 	return url.substr(at + 1 - url.c_str()); | ||||
| } | ||||
| 
 | ||||
| extern "C" void cleanup_git_info(struct git_info *info) | ||||
| git_info::git_info() : repo(nullptr), is_subsurface_cloud(0), transport(RT_LOCAL) | ||||
| { | ||||
| 	if (info->repo) | ||||
| 		git_repository_free(info->repo); | ||||
| 	free((void *)info->url); | ||||
| 	free((void *)info->branch); | ||||
| 	free((void *)info->username); | ||||
| 	free((void *)info->localdir); | ||||
| 	memset(info, 0, sizeof(*info)); | ||||
| } | ||||
| 
 | ||||
| git_info::~git_info() | ||||
| { | ||||
| 	if (repo) | ||||
| 		git_repository_free(repo); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -1018,16 +1020,14 @@ extern "C" void cleanup_git_info(struct git_info *info) | |||
|  *    https://host/repo[branch]
 | ||||
|  *    file://repo[branch]
 | ||||
|  */ | ||||
| extern "C" bool is_git_repository(const char *filename, struct git_info *info) | ||||
| bool is_git_repository(const char *filename, struct git_info *info) | ||||
| { | ||||
| 	int flen, blen; | ||||
| 	int offset = 1; | ||||
| 	char *url, *branch; | ||||
| 
 | ||||
| 	/* we are looking at a new potential remote, but we haven't synced with it */ | ||||
| 	git_remote_sync_successful = false; | ||||
| 
 | ||||
| 	memset(info, 0, sizeof(*info)); | ||||
| 	info->transport = RT_LOCAL; | ||||
| 	flen = strlen(filename); | ||||
| 	if (!flen || filename[--flen] != ']') | ||||
|  | @ -1070,11 +1070,11 @@ extern "C" bool is_git_repository(const char *filename, struct git_info *info) | |||
| 	 * The actual git reading/writing routines can use this | ||||
| 	 * to generate proper error messages. | ||||
| 	 */ | ||||
| 	url = format_string("%.*s", flen, filename); | ||||
| 	branch = format_string("%.*s", blen, filename + flen + offset); | ||||
| 	std::string url(filename, flen); | ||||
| 	std::string branch(filename + flen + offset, blen); | ||||
| 
 | ||||
| 	/* Extract the username from the url string */ | ||||
| 	extract_username(info, url); | ||||
| 	url = extract_username(info, url); | ||||
| 
 | ||||
| 	info->url = url; | ||||
| 	info->branch = branch; | ||||
|  | @ -1099,10 +1099,10 @@ extern "C" bool is_git_repository(const char *filename, struct git_info *info) | |||
| 	 */ | ||||
| 	switch (info->transport) { | ||||
| 	case RT_LOCAL: | ||||
| 		info->localdir = strdup(url); | ||||
| 		info->localdir = url; | ||||
| 		break; | ||||
| 	default: | ||||
| 		info->localdir = get_local_dir(info->url, info->branch); | ||||
| 		info->localdir = get_local_dir(info->url.c_str(), info->branch).c_str(); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1112,19 +1112,19 @@ extern "C" bool is_git_repository(const char *filename, struct git_info *info) | |||
| 	 * | ||||
| 	 * This is used to create more user friendly error message and warnings. | ||||
| 	 */ | ||||
| 	info->is_subsurface_cloud = (strstr(info->url, prefs.cloud_base_url) != NULL); | ||||
| 	info->is_subsurface_cloud = (strstr(info->url.c_str(), prefs.cloud_base_url) != NULL); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| extern "C" bool open_git_repository(struct git_info *info) | ||||
| bool open_git_repository(struct git_info *info) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * If the repository is local, just open it. There's nothing | ||||
| 	 * else to do. | ||||
| 	 */ | ||||
| 	if (info->transport == RT_LOCAL) { | ||||
| 		const char *url = info->localdir; | ||||
| 		const char *url = info->localdir.c_str(); | ||||
| 
 | ||||
| 		if (git_repository_open(&info->repo, url)) { | ||||
| 			if (verbose) | ||||
|  | @ -1145,15 +1145,13 @@ extern "C" bool open_git_repository(struct git_info *info) | |||
| 	return get_remote_repo(info); | ||||
| } | ||||
| 
 | ||||
| extern "C" int git_create_local_repo(const char *filename) | ||||
| int git_create_local_repo(const std::string &filename) | ||||
| { | ||||
| 	git_repository *repo; | ||||
| 	char *path = strdup(filename); | ||||
| 	char *branch = strchr(path, '['); | ||||
| 	if (branch) | ||||
| 		*branch = '\0'; | ||||
| 	int ret = git_repository_init(&repo, path, false); | ||||
| 	free(path); | ||||
| 
 | ||||
| 	auto idx = filename.find('['); | ||||
| 	std::string path = filename.substr(0, idx); | ||||
| 	int ret = git_repository_init(&repo, path.c_str(), false); | ||||
| 	if (ret != 0) | ||||
| 		(void)report_error("Create local repo failed with error code %d", ret); | ||||
| 	git_repository_free(repo); | ||||
|  |  | |||
|  | @ -22,20 +22,38 @@ extern "C" { | |||
| 
 | ||||
| enum remote_transport { RT_LOCAL, RT_HTTPS, RT_SSH, RT_OTHER }; | ||||
| 
 | ||||
| extern bool git_local_only; | ||||
| extern bool git_remote_sync_successful; | ||||
| extern void clear_git_id(void); | ||||
| extern void set_git_id(const struct git_oid *); | ||||
| void set_git_update_cb(int(*)(const char *)); | ||||
| int git_storage_update_progress(const char *text); | ||||
| int get_authorship(git_repository *repo, git_signature **authorp); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| struct git_oid; | ||||
| struct git_repository; | ||||
| struct divelog; | ||||
| 
 | ||||
| struct git_info { | ||||
| 	const char *url; | ||||
| 	const char *branch; | ||||
| 	const char *username; | ||||
| 	const char *localdir; | ||||
| 	std::string url; | ||||
| 	std::string branch; | ||||
| 	std::string username; | ||||
| 	std::string localdir; | ||||
| 	struct git_repository *repo; | ||||
| 	unsigned is_subsurface_cloud:1; | ||||
| 	enum remote_transport transport; | ||||
| 	git_info(); | ||||
| 	~git_info(); | ||||
| }; | ||||
| 
 | ||||
| extern std::string saved_git_id; | ||||
| extern std::string get_sha(git_repository *repo, const std::string &branch); | ||||
| extern std::string get_local_dir(const std::string &, const std::string &); | ||||
| extern bool is_git_repository(const char *filename, struct git_info *info); | ||||
| extern bool open_git_repository(struct git_info *info); | ||||
| extern bool remote_repo_uptodate(const char *filename, struct git_info *info); | ||||
|  | @ -43,23 +61,7 @@ extern int sync_with_remote(struct git_info *); | |||
| extern int git_save_dives(struct git_info *, bool select_only); | ||||
| extern int git_load_dives(struct git_info *, struct divelog *log); | ||||
| extern int do_git_save(struct git_info *, bool select_only, bool create_empty); | ||||
| extern void cleanup_git_info(struct git_info *); | ||||
| extern bool git_local_only; | ||||
| extern bool git_remote_sync_successful; | ||||
| extern void clear_git_id(void); | ||||
| extern void set_git_id(const struct git_oid *); | ||||
| void set_git_update_cb(int(*)(const char *)); | ||||
| int git_storage_update_progress(const char *text); | ||||
| char *get_local_dir(const char *, const char *); | ||||
| int git_create_local_repo(const char *filename); | ||||
| int get_authorship(git_repository *repo, git_signature **authorp); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| 
 | ||||
| #include <string> | ||||
| extern std::string saved_git_id; | ||||
| extern std::string get_sha(git_repository *repo, const char *branch); | ||||
| extern int git_create_local_repo(const std::string &filename); | ||||
| 
 | ||||
| #endif | ||||
| #endif // GITACCESS_H
 | ||||
|  |  | |||
|  | @ -1895,11 +1895,11 @@ static int do_git_load(git_repository *repo, const char *branch, struct git_pars | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| std::string get_sha(git_repository *repo, const char *branch) | ||||
| std::string get_sha(git_repository *repo, const std::string &branch) | ||||
| { | ||||
| 	char git_id_buffer[GIT_OID_HEXSZ + 1]; | ||||
| 	git_commit *commit; | ||||
| 	if (find_commit(repo, branch, &commit)) | ||||
| 	if (find_commit(repo, branch.c_str(), &commit)) | ||||
| 		return std::string(); | ||||
| 	git_oid_tostr(git_id_buffer, sizeof(git_id_buffer), (const git_oid *)commit); | ||||
| 	return std::string(git_id_buffer); | ||||
|  | @ -1913,7 +1913,7 @@ std::string get_sha(git_repository *repo, const char *branch) | |||
|  * If it is a git repository, we return zero for success, | ||||
|  * or report an error and return 1 if the load failed. | ||||
|  */ | ||||
| extern "C" int git_load_dives(struct git_info *info, struct divelog *log) | ||||
| int git_load_dives(struct git_info *info, struct divelog *log) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct git_parser_state state; | ||||
|  | @ -1921,8 +1921,8 @@ extern "C" int git_load_dives(struct git_info *info, struct divelog *log) | |||
| 	state.log = log; | ||||
| 
 | ||||
| 	if (!info->repo) | ||||
| 		return report_error("Unable to open git repository '%s[%s]'", info->url, info->branch); | ||||
| 	ret = do_git_load(info->repo, info->branch, &state); | ||||
| 		return report_error("Unable to open git repository '%s[%s]'", info->url.c_str(), info->branch.c_str()); | ||||
| 	ret = do_git_load(info->repo, info->branch.c_str(), &state); | ||||
| 	finish_active_dive(&state); | ||||
| 	finish_active_trip(&state); | ||||
| 	return ret; | ||||
|  |  | |||
|  | @ -22,7 +22,6 @@ | |||
| #include "tag.h" | ||||
| #include "imagedownloader.h" | ||||
| #include "xmlparams.h" | ||||
| #include "core/git-access.h" // for CLOUD_HOST definitions
 | ||||
| #include <QFile> | ||||
| #include <QRegularExpression> | ||||
| #include <QDir> | ||||
|  | @ -331,31 +330,31 @@ extern "C" xsltStylesheetPtr get_stylesheet(const char *name) | |||
| 	return xslt; | ||||
| } | ||||
| 
 | ||||
| extern "C" char *move_away(const char *old_path) | ||||
| std::string move_away(const std::string &old_path) | ||||
| { | ||||
| 	if (verbose > 1) | ||||
| 		qDebug() << "move away" << old_path; | ||||
| 	QDir oldDir(old_path); | ||||
| 		qDebug() << "move away" << old_path.c_str(); | ||||
| 	QDir oldDir(old_path.c_str()); | ||||
| 	QDir newDir; | ||||
| 	QString newPath; | ||||
| 	std::string newPath; | ||||
| 	int i = 0; | ||||
| 	do { | ||||
| 		newPath = QString(old_path) + QString(".%1").arg(++i); | ||||
| 		newDir.setPath(newPath); | ||||
| 		newPath = old_path + "." + std::to_string(++i); | ||||
| 		newDir.setPath(newPath.c_str()); | ||||
| 	} while(newDir.exists()); | ||||
| 	if (verbose > 1) | ||||
| 		qDebug() << "renaming to" << newPath; | ||||
| 	if (!oldDir.rename(old_path, newPath)) { | ||||
| 		qDebug() << "renaming to" << newPath.c_str(); | ||||
| 	if (!oldDir.rename(old_path.c_str(), newPath.c_str())) { | ||||
| 		if (verbose) | ||||
| 			qDebug() << "rename of" << old_path << "to" << newPath << "failed"; | ||||
| 			qDebug() << "rename of" << old_path.c_str() << "to" << newPath.c_str() << "failed"; | ||||
| 		// this next one we only try on Windows... if we are on a different platform
 | ||||
| 		// we simply give up and return an empty string
 | ||||
| #ifdef WIN32 | ||||
| 		if (subsurface_dir_rename(old_path, qPrintable(newPath)) == 0) | ||||
| 		if (subsurface_dir_rename(old_path.c_str(), newPath.c_str()) == 0) | ||||
| #endif | ||||
| 			return strdup(""); | ||||
| 			return std::string(); | ||||
| 	} | ||||
| 	return copy_qstring(newPath); | ||||
| 	return newPath; | ||||
| } | ||||
| 
 | ||||
| std::string get_file_name(const char *fileName) | ||||
|  | @ -1375,31 +1374,6 @@ extern "C" char *cloud_url() | |||
| 	return copy_qstring(filename); | ||||
| } | ||||
| 
 | ||||
| std::string normalize_cloud_name(const char *remote_in) | ||||
| { | ||||
| 	// replace ssrf-cloud-XX.subsurface... names with cloud.subsurface... names
 | ||||
| 	// that trailing '/' is to match old code
 | ||||
| 	QString ri(remote_in); | ||||
| 	ri.replace(QRegularExpression(CLOUD_HOST_PATTERN), CLOUD_HOST_GENERIC "/"); | ||||
| 	return ri.toStdString(); | ||||
| } | ||||
| 
 | ||||
| extern "C" bool getProxyString(char **buffer) | ||||
| { | ||||
| 	if (prefs.proxy_type == QNetworkProxy::HttpProxy) { | ||||
| 		QString proxy; | ||||
| 		if (prefs.proxy_auth) | ||||
| 			proxy = QString("http://%1:%2@%3:%4").arg(prefs.proxy_user).arg(prefs.proxy_pass) | ||||
| 					.arg(prefs.proxy_host).arg(prefs.proxy_port); | ||||
| 		else | ||||
| 			proxy = QString("http://%1:%2").arg(prefs.proxy_host).arg(prefs.proxy_port); | ||||
| 		if (buffer) | ||||
| 			*buffer = copy_qstring(proxy); | ||||
| 		return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| extern "C" void subsurface_mkdir(const char *dir) | ||||
| { | ||||
| 	QDir directory; | ||||
|  |  | |||
|  | @ -103,8 +103,8 @@ extern QString (*changesCallback)(); | |||
| void uiNotification(const QString &msg); | ||||
| std::string get_changes_made(); | ||||
| std::string subsurface_user_agent(); | ||||
| std::string normalize_cloud_name(const char *remote_in); | ||||
| std::string get_file_name(const char *fileName); | ||||
| std::string move_away(const std::string &path); | ||||
| 
 | ||||
| #if defined __APPLE__ | ||||
| #define TITLE_OR_TEXT(_t, _m) "", _t + "\n" + _m | ||||
|  | @ -122,12 +122,10 @@ extern "C" { | |||
| 
 | ||||
| struct git_info; | ||||
| 
 | ||||
| bool getProxyString(char **buffer); | ||||
| bool canReachCloudServer(struct git_info *); | ||||
| void updateWindowTitle(); | ||||
| void subsurface_mkdir(const char *dir); | ||||
| void copy_image_and_overwrite(const char *cfileName, const char *path, const char *cnewName); | ||||
| char *move_away(const char *path); | ||||
| const char *local_file_path(struct picture *picture); | ||||
| char *cloud_url(); | ||||
| char *hashfile_name_string(); | ||||
|  |  | |||
|  | @ -1177,19 +1177,19 @@ static int create_new_commit(struct git_info *info, git_oid *tree_id, bool creat | |||
| 	git_commit *commit; | ||||
| 	git_tree *tree; | ||||
| 
 | ||||
| 	ret = git_branch_lookup(&ref, info->repo, info->branch, GIT_BRANCH_LOCAL); | ||||
| 	ret = git_branch_lookup(&ref, info->repo, info->branch.c_str(), GIT_BRANCH_LOCAL); | ||||
| 	switch (ret) { | ||||
| 	default: | ||||
| 		return report_error("Bad branch '%s' (%s)", info->branch, strerror(errno)); | ||||
| 		return report_error("Bad branch '%s' (%s)", info->branch.c_str(), strerror(errno)); | ||||
| 	case GIT_EINVALIDSPEC: | ||||
| 		return report_error("Invalid branch name '%s'", info->branch); | ||||
| 		return report_error("Invalid branch name '%s'", info->branch.c_str()); | ||||
| 	case GIT_ENOTFOUND: /* We'll happily create it */ | ||||
| 		ref = NULL; | ||||
| 		parent = try_to_find_parent(saved_git_id.c_str(), info->repo); | ||||
| 		break; | ||||
| 	case 0: | ||||
| 		if (git_reference_peel(&parent, ref, GIT_OBJ_COMMIT)) | ||||
| 			return report_error("Unable to look up parent in branch '%s'", info->branch); | ||||
| 			return report_error("Unable to look up parent in branch '%s'", info->branch.c_str()); | ||||
| 
 | ||||
| 		if (!saved_git_id.empty()) { | ||||
| 			if (!existing_filename.empty() && verbose) | ||||
|  | @ -1238,8 +1238,8 @@ static int create_new_commit(struct git_info *info, git_oid *tree_id, bool creat | |||
| 	git_signature_free(author); | ||||
| 
 | ||||
| 	if (!ref) { | ||||
| 		if (git_branch_create(&ref, info->repo, info->branch, commit, 0)) | ||||
| 			return report_error("Failed to create branch '%s'", info->branch); | ||||
| 		if (git_branch_create(&ref, info->repo, info->branch.c_str(), commit, 0)) | ||||
| 			return report_error("Failed to create branch '%s'", info->branch.c_str()); | ||||
| 	} | ||||
| 	/*
 | ||||
| 	 * If it's a checked-out branch, try to also update the working | ||||
|  | @ -1253,12 +1253,12 @@ static int create_new_commit(struct git_info *info, git_oid *tree_id, bool creat | |||
| 			const git_error *err = giterr_last(); | ||||
| 			const char *errstr = err ? err->message : strerror(errno); | ||||
| 			report_error("Git branch '%s' is checked out, but worktree is dirty (%s)", | ||||
| 				info->branch, errstr); | ||||
| 				info->branch.c_str(), errstr); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (git_reference_set_target(&ref, ref, &commit_id, "Subsurface save event")) | ||||
| 		return report_error("Failed to update branch '%s'", info->branch); | ||||
| 		return report_error("Failed to update branch '%s'", info->branch.c_str()); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * if this was the empty commit to initialize a new repo, don't remember the | ||||
|  | @ -1294,14 +1294,14 @@ static int write_git_tree(git_repository *repo, const struct dir *tree, git_oid | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| extern "C" int do_git_save(struct git_info *info, bool select_only, bool create_empty) | ||||
| int do_git_save(struct git_info *info, bool select_only, bool create_empty) | ||||
| { | ||||
| 	struct dir tree; | ||||
| 	git_oid id; | ||||
| 	bool cached_ok; | ||||
| 
 | ||||
| 	if (!info->repo) | ||||
| 		return report_error("Unable to open git repository '%s[%s]'", info->url, info->branch); | ||||
| 		return report_error("Unable to open git repository '%s[%s]'", info->url.c_str(), info->branch.c_str()); | ||||
| 
 | ||||
| 	if (verbose) | ||||
| 		report_info("git storage: do git save\n"); | ||||
|  | @ -1335,12 +1335,12 @@ extern "C" int do_git_save(struct git_info *info, bool select_only, bool create_ | |||
| 		return report_error("creating commit failed"); | ||||
| 
 | ||||
| 	/* now sync the tree with the remote server */ | ||||
| 	if (info->url && !git_local_only) | ||||
| 	if (!info->url.empty() && !git_local_only) | ||||
| 		return sync_with_remote(info); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| extern "C" int git_save_dives(struct git_info *info, bool select_only) | ||||
| int git_save_dives(struct git_info *info, bool select_only) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * First, just try to open the local git repo without | ||||
|  | @ -1357,7 +1357,7 @@ extern "C" int git_save_dives(struct git_info *info, bool select_only) | |||
| 	 * at least the local state will be saved early in | ||||
| 	 * case something goes wrong. | ||||
| 	 */ | ||||
| 	if (!git_repository_open(&info->repo, info->localdir)) | ||||
| 	if (!git_repository_open(&info->repo, info->localdir.c_str())) | ||||
| 		return do_git_save(info, select_only, false); | ||||
| 
 | ||||
| 	/*
 | ||||
|  | @ -1369,7 +1369,7 @@ extern "C" int git_save_dives(struct git_info *info, bool select_only) | |||
| 	 * This shouldn't be the common case. | ||||
| 	 */ | ||||
| 	if (!open_git_repository(info)) | ||||
| 		return report_error(translate("gettextFromC", "Failed to save dives to %s[%s] (%s)"), info->url, info->branch, strerror(errno)); | ||||
| 		return report_error(translate("gettextFromC", "Failed to save dives to %s[%s] (%s)"), info->url.c_str(), info->branch.c_str(), strerror(errno)); | ||||
| 
 | ||||
| 	return do_git_save(info, select_only, false); | ||||
| } | ||||
|  |  | |||
|  | @ -823,7 +823,6 @@ extern "C" int save_dives_logic(const char *filename, const bool select_only, bo | |||
| 
 | ||||
| 	if (is_git_repository(filename, &info)) { | ||||
| 		error = git_save_dives(&info, select_only); | ||||
| 		cleanup_git_info(&info); | ||||
| 		return error; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ extern "C" void print_version() | |||
| 
 | ||||
| extern "C" void print_files() | ||||
| { | ||||
| 	struct git_info info = { }; | ||||
| 	struct git_info info; | ||||
| 	const char *filename; | ||||
| 
 | ||||
| 	printf("\nFile locations:\n\n"); | ||||
|  | @ -58,12 +58,11 @@ extern "C" void print_files() | |||
| 		/* strdup so the free below works in either case */ | ||||
| 		filename = strdup("No valid cloud credentials set.\n"); | ||||
| 	} | ||||
| 	if (info.localdir) { | ||||
| 		printf("Local git storage: %s\n", info.localdir); | ||||
| 	if (!info.localdir.empty()) { | ||||
| 		printf("Local git storage: %s\n", info.localdir.c_str()); | ||||
| 	} else { | ||||
| 		printf("Unable to get local git directory\n"); | ||||
| 	} | ||||
| 	cleanup_git_info(&info); | ||||
| 	printf("Cloud URL: %s\n", filename); | ||||
| 	free((void *)filename); | ||||
| 	char *tmp = hashfile_name_string(); | ||||
|  |  | |||
|  | @ -804,7 +804,7 @@ void QMLManager::loadDivesWithValidCredentials() | |||
| 			appendTextToLog("Switching from no cloud mode; keep in memory dive data"); | ||||
| 		} | ||||
| 		if (info.repo) { | ||||
| 			appendTextToLog(QString("have repository and branch %1").arg(info.branch)); | ||||
| 			appendTextToLog(QString("have repository and branch %1").arg(info.branch.c_str())); | ||||
| 			error = git_load_dives(&info, &divelog); | ||||
| 		} else { | ||||
| 			appendTextToLog(QString("didn't receive valid git repo, try again")); | ||||
|  | @ -823,7 +823,6 @@ void QMLManager::loadDivesWithValidCredentials() | |||
| 		} | ||||
| 		consumeFinishedLoad(); | ||||
| 	} | ||||
| 	cleanup_git_info(&info); | ||||
| 
 | ||||
| 	setLoadFromCloud(true); | ||||
| 
 | ||||
|  | @ -1501,7 +1500,7 @@ void QMLManager::openNoCloudRepo() | |||
| 	appendTextToLog(QString("User asked not to connect to cloud, using %1 as repo.").arg(filename)); | ||||
| 	if (is_git_repository(qPrintable(filename), &info) && !open_git_repository(&info)) { | ||||
| 		// repo doesn't exist, create it and write the empty dive list to it
 | ||||
| 		git_create_local_repo(qPrintable(filename)); | ||||
| 		git_create_local_repo(filename.toStdString()); | ||||
| 		save_dives(qPrintable(filename)); | ||||
| 		existing_filename = filename.toStdString(); | ||||
| 		auto s = qPrefLog::instance(); | ||||
|  | @ -1517,7 +1516,7 @@ void QMLManager::saveChangesLocal() | |||
| 		if (qPrefCloudStorage::cloud_verification_status() == qPrefCloudStorage::CS_NOCLOUD) { | ||||
| 			if (existing_filename.empty()) { | ||||
| 				QString filename = nocloud_localstorage(); | ||||
| 				git_create_local_repo(qPrintable(filename)); | ||||
| 				git_create_local_repo(filename.toStdString()); | ||||
| 				existing_filename = filename.toStdString(); | ||||
| 				auto s = qPrefLog::instance(); | ||||
| 				s->set_default_filename(qPrintable(filename)); | ||||
|  |  | |||
|  | @ -7,6 +7,8 @@ | |||
| #include "core/divelist.h" | ||||
| #include "core/divelog.h" | ||||
| #include "core/file.h" | ||||
| #include "core/subsurface-string.h" | ||||
| #include "core/format.h" | ||||
| #include "core/qthelper.h" | ||||
| #include "core/subsurfacestartup.h" | ||||
| #include "core/settings/qPrefProxy.h" | ||||
|  | @ -23,34 +25,36 @@ | |||
| #endif | ||||
| 
 | ||||
| // provide declarations for two local helper functions in git-access.c
 | ||||
| extern "C" char *get_local_dir(const char *remote, const char *branch); | ||||
| extern "C" void delete_remote_branch(git_repository *repo, const char *remote, const char *branch); | ||||
| std::string get_local_dir(const std::string &remote, const std::string &branch); | ||||
| void delete_remote_branch(git_repository *repo, const std::string &remote, const std::string &branch); | ||||
| 
 | ||||
| QString email; | ||||
| QString gitUrl; | ||||
| QString cloudTestRepo; | ||||
| QString localCacheDir; | ||||
| QString localCacheRepo; | ||||
| QString randomBranch; | ||||
| Q_DECLARE_METATYPE(std::string); | ||||
| 
 | ||||
| static void moveDir(QString oldName, QString newName) | ||||
| std::string email; | ||||
| std::string gitUrl; | ||||
| std::string cloudTestRepo; | ||||
| std::string localCacheDir; | ||||
| std::string localCacheRepo; | ||||
| std::string randomBranch; | ||||
| 
 | ||||
| static void moveDir(const std::string &oldName, const std::string &newName) | ||||
| { | ||||
| 	QDir oldDir(oldName); | ||||
| 	QDir newDir(newName); | ||||
| 	QDir oldDir(oldName.c_str()); | ||||
| 	QDir newDir(newName.c_str()); | ||||
| 	QCOMPARE(newDir.removeRecursively(), true); | ||||
| 	QCOMPARE(oldDir.rename(oldName, newName), true); | ||||
| 	QCOMPARE(oldDir.rename(oldName.c_str(), newName.c_str()), true); | ||||
| } | ||||
| 
 | ||||
| static void localRemoteCleanup() | ||||
| { | ||||
| 	// cleanup the local cache dir
 | ||||
| 	struct git_info info = { }; | ||||
| 	QDir localCacheDirectory(localCacheDir); | ||||
| 	struct git_info info; | ||||
| 	QDir localCacheDirectory(localCacheDir.c_str()); | ||||
| 	QCOMPARE(localCacheDirectory.removeRecursively(), true); | ||||
| 
 | ||||
| 	// when this is first executed, we expect the branch not to exist on the remote server;
 | ||||
| 	// if that's true, this will print a harmless error to stderr
 | ||||
| 	is_git_repository(qPrintable(cloudTestRepo), &info) && open_git_repository(&info); | ||||
| 	is_git_repository(cloudTestRepo.c_str(), &info) && open_git_repository(&info); | ||||
| 
 | ||||
| 	// this odd comparison is used to tell that we were able to connect to the remote repo;
 | ||||
| 	// in the error case we get the full cloudTestRepo name back as "branch"
 | ||||
|  | @ -65,8 +69,6 @@ static void localRemoteCleanup() | |||
| 
 | ||||
| 	// and since this will have created a local repo, remove that one, again so the tests start clean
 | ||||
| 	QCOMPARE(localCacheDirectory.removeRecursively(), true); | ||||
| 
 | ||||
| 	cleanup_git_info(&info); | ||||
| } | ||||
| 
 | ||||
| void TestGitStorage::initTestCase() | ||||
|  | @ -88,50 +90,50 @@ void TestGitStorage::initTestCase() | |||
| 	//
 | ||||
| 	// To reduce the risk of collisions on the server, we have ten accounts set up for this purpose
 | ||||
| 	// please don't use them for other reasons as they will get deleted regularly
 | ||||
| 	email = qgetenv("SSRF_USER_EMAIL"); | ||||
| 	QString password = qgetenv("SSRF_USER_PASSWORD"); | ||||
| 	email = qgetenv("SSRF_USER_EMAIL").toStdString(); | ||||
| 	std::string password(qgetenv("SSRF_USER_PASSWORD").data()); | ||||
| 
 | ||||
| 	if (email.isEmpty()) { | ||||
| 	if (email.empty()) { | ||||
| #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) | ||||
| 		email = QString("gitstorage%1@hohndel.org").arg(QRandomGenerator::global()->bounded(10)); | ||||
| 		email = format_string_std("gitstorage%d@hohndel.org", QRandomGenerator::global()->bounded(10)); | ||||
| #else | ||||
| 		// on Qt 5.9 we go back to using qsrand()/qrand()
 | ||||
| 		qsrand(time(NULL)); | ||||
| 		email = QString("gitstorage%1@hohndel.org").arg(qrand() % 10); | ||||
| 		email = format_string_std("gitstorage%d@hohndel.org", qrand() % 10); | ||||
| #endif | ||||
| 	} | ||||
| 	if (password.isEmpty()) | ||||
| 	if (password.empty()) | ||||
| 		password = "please-only-use-this-in-the-git-tests"; | ||||
| 	gitUrl = prefs.cloud_base_url; | ||||
| 	if (gitUrl.right(1) != "/") | ||||
| 	if (gitUrl.empty() || gitUrl.back() != '/') | ||||
| 		gitUrl += "/"; | ||||
| 	gitUrl += "git"; | ||||
| 	prefs.cloud_storage_email_encoded = copy_qstring(email); | ||||
| 	prefs.cloud_storage_password = copy_qstring(password); | ||||
| 	prefs.cloud_storage_email_encoded = strdup(email.c_str()); | ||||
| 	prefs.cloud_storage_password = strdup(password.c_str()); | ||||
| 	gitUrl += "/" + email; | ||||
| 	// all user storage for historical reasons always uses the user's email both as
 | ||||
| 	// repo name and as branch. To allow us to keep testing and not step on parallel
 | ||||
| 	// runs we'll use actually random branch names - yes, this still has a chance of
 | ||||
| 	// conflict, but I'm not going to implement a distributed lock manager for this
 | ||||
| 	if (email.startsWith("gitstorage")) { | ||||
| 	if (starts_with(email, "gitstorage")) { | ||||
| #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) | ||||
| 		randomBranch = QString::number(QRandomGenerator::global()->bounded(0x1000000), 16) + | ||||
| 				QString::number(QRandomGenerator::global()->bounded(0x1000000), 16); | ||||
| 		randomBranch = format_string_std("%x%x", QRandomGenerator::global()->bounded(0x1000000), | ||||
| 				QRandomGenerator::global()->bounded(0x1000000)); | ||||
| #else | ||||
| 		// on Qt 5.9 we go back to using qsrand()/qrand() -- if we get to this code, qsrand() was already called
 | ||||
| 		// even on a 32bit system RAND_MAX is at least 32767 so this will also give us 12 random hex digits
 | ||||
| 		randomBranch = QString::number(qrand() % 0x1000, 16) + QString::number(qrand() % 0x1000, 16) + | ||||
| 				QString::number(qrand() % 0x1000, 16) + QString::number(qrand() % 0x1000, 16); | ||||
| 		randomBranch = format_string_std("%x%x%x%x", qrand() % 0x1000, qrand() % 0x1000, | ||||
| 				qrand() % 0x1000, qrand() % 0x1000); | ||||
| #endif | ||||
| 	} else { | ||||
| 		// user supplied their own credentials, fall back to the usual "email is branch" pattern
 | ||||
| 		randomBranch = email; | ||||
| 	} | ||||
| 	cloudTestRepo = gitUrl + QStringLiteral("[%1]").arg(randomBranch); | ||||
| 	localCacheDir = get_local_dir(qPrintable(gitUrl), qPrintable(randomBranch)); | ||||
| 	localCacheRepo = localCacheDir + QStringLiteral("[%1]").arg(randomBranch); | ||||
| 	qDebug() << "repo used:" << cloudTestRepo; | ||||
| 	qDebug() << "local cache:" << localCacheRepo; | ||||
| 	cloudTestRepo = gitUrl + "[" + randomBranch + ']'; | ||||
| 	localCacheDir = get_local_dir(gitUrl.c_str(), randomBranch.c_str()); | ||||
| 	localCacheRepo = localCacheDir + "[" + randomBranch + "]"; | ||||
| 	qDebug() << "repo used:" << cloudTestRepo.c_str(); | ||||
| 	qDebug() << "local cache:" << localCacheRepo.c_str(); | ||||
| 
 | ||||
| 	// make sure we deal with any proxy settings that are needed
 | ||||
| 	QNetworkProxy proxy; | ||||
|  | @ -152,7 +154,7 @@ void TestGitStorage::initTestCase() | |||
| 
 | ||||
| 	// cleanup local and remote branches
 | ||||
| 	localRemoteCleanup(); | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| } | ||||
| 
 | ||||
| void TestGitStorage::cleanupTestCase() | ||||
|  | @ -169,15 +171,16 @@ void TestGitStorage::testGitStorageLocal_data() | |||
| { | ||||
| 	// Test different paths we may encounter (since storage depends on user name)
 | ||||
| 	// as well as with and without "file://" URL prefix.
 | ||||
| 	QTest::addColumn<QString>("testDirName"); | ||||
| 	QTest::addColumn<QString>("prefixRead"); | ||||
| 	QTest::addColumn<QString>("prefixWrite"); | ||||
| 	QTest::newRow("ASCII path") << "./gittest" << "" << ""; | ||||
| 	QTest::newRow("Non ASCII path") << "./gittest_éèêôàüäößíñóúäåöø" << "" << ""; | ||||
| 	QTest::newRow("ASCII path with file:// prefix on read") << "./gittest2" << "file://" << ""; | ||||
| 	QTest::newRow("Non ASCII path with file:// prefix on read") << "./gittest2_éèêôàüäößíñóúäåöø" << "" << "file://"; | ||||
| 	QTest::newRow("ASCII path with file:// prefix on write") << "./gittest3" << "file://" << ""; | ||||
| 	QTest::newRow("Non ASCII path with file:// prefix on write") << "./gittest3_éèêôàüäößíñóúäåöø" << "" << "file://"; | ||||
| 	using namespace std::string_literals; // For std::string literals: "some string"s.
 | ||||
| 	QTest::addColumn<std::string>("testDirName"); | ||||
| 	QTest::addColumn<std::string>("prefixRead"); | ||||
| 	QTest::addColumn<std::string>("prefixWrite"); | ||||
| 	QTest::newRow("ASCII path") << "./gittest"s << ""s << ""s; | ||||
| 	QTest::newRow("Non ASCII path") << "./gittest_éèêôàüäößíñóúäåöø"s << ""s << ""s; | ||||
| 	QTest::newRow("ASCII path with file:// prefix on read") << "./gittest2"s << "file://"s << ""s; | ||||
| 	QTest::newRow("Non ASCII path with file:// prefix on read") << "./gittest2_éèêôàüäößíñóúäåöø"s << ""s << "file://"s; | ||||
| 	QTest::newRow("ASCII path with file:// prefix on write") << "./gittest3"s << "file://"s << ""s; | ||||
| 	QTest::newRow("Non ASCII path with file:// prefix on write") << "./gittest3_éèêôàüäößíñóúäåöø"s << ""s << "file://"s; | ||||
| } | ||||
| 
 | ||||
| void TestGitStorage::testGitStorageLocal() | ||||
|  | @ -185,19 +188,19 @@ void TestGitStorage::testGitStorageLocal() | |||
| 	// test writing and reading back from local git storage
 | ||||
| 	git_repository *repo; | ||||
| 	QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/SampleDivesV2.ssrf", &divelog), 0); | ||||
| 	QFETCH(QString, testDirName); | ||||
| 	QFETCH(QString, prefixRead); | ||||
| 	QFETCH(QString, prefixWrite); | ||||
| 	QDir testDir(testDirName); | ||||
| 	QFETCH(std::string, testDirName); | ||||
| 	QFETCH(std::string, prefixRead); | ||||
| 	QFETCH(std::string, prefixWrite); | ||||
| 	QDir testDir(testDirName.c_str()); | ||||
| 	QCOMPARE(testDir.removeRecursively(), true); | ||||
| 	QCOMPARE(QDir().mkdir(testDirName), true); | ||||
| 	QString repoNameRead = prefixRead + testDirName; | ||||
| 	QString repoNameWrite = prefixWrite + testDirName; | ||||
| 	QCOMPARE(git_repository_init(&repo, qPrintable(testDirName), false), 0); | ||||
| 	QCOMPARE(save_dives(qPrintable(repoNameWrite + "[test]")), 0); | ||||
| 	QCOMPARE(QDir().mkdir(testDirName.c_str()), true); | ||||
| 	std::string repoNameRead = prefixRead + testDirName; | ||||
| 	std::string repoNameWrite = prefixWrite + testDirName; | ||||
| 	QCOMPARE(git_repository_init(&repo, testDirName.c_str(), false), 0); | ||||
| 	QCOMPARE(save_dives((repoNameWrite + "[test]").c_str()), 0); | ||||
| 	QCOMPARE(save_dives("./SampleDivesV3.ssrf"), 0); | ||||
| 	clear_dive_file_data(); | ||||
| 	QCOMPARE(parse_file(qPrintable(repoNameRead + "[test]"), &divelog), 0); | ||||
| 	QCOMPARE(parse_file((repoNameRead + "[test]").c_str(), &divelog), 0); | ||||
| 	QCOMPARE(save_dives("./SampleDivesV3viagit.ssrf"), 0); | ||||
| 	QFile org("./SampleDivesV3.ssrf"); | ||||
| 	org.open(QFile::ReadOnly); | ||||
|  | @ -216,9 +219,9 @@ void TestGitStorage::testGitStorageCloud() | |||
| 	// connect to the ssrftest repository on the cloud server
 | ||||
| 	// and repeat the same test as before with the local git storage
 | ||||
| 	QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/SampleDivesV2.ssrf", &divelog), 0); | ||||
| 	QCOMPARE(save_dives(qPrintable(cloudTestRepo)), 0); | ||||
| 	QCOMPARE(save_dives(cloudTestRepo.c_str()), 0); | ||||
| 	clear_dive_file_data(); | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	QCOMPARE(save_dives("./SampleDivesV3viacloud.ssrf"), 0); | ||||
| 	QFile org("./SampleDivesV3.ssrf"); | ||||
| 	org.open(QFile::ReadOnly); | ||||
|  | @ -236,19 +239,19 @@ void TestGitStorage::testGitStorageCloudOfflineSync() | |||
| 	// make a change to local cache repo (pretending that we did some offline changes)
 | ||||
| 	// and then open the remote one again and check that things were propagated correctly
 | ||||
| 	// read the local repo from the previous test and add dive 10
 | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test10.xml", &divelog), 0); | ||||
| 	// calling process_loaded_dives() sorts the table, but calling add_imported_dives()
 | ||||
| 	// causes it to try to update the window title... let's not do that
 | ||||
| 	process_loaded_dives(); | ||||
| 	// now save only to the local cache but not to the remote server
 | ||||
| 	git_local_only = true; | ||||
| 	QCOMPARE(save_dives(qPrintable(cloudTestRepo)), 0); | ||||
| 	QCOMPARE(save_dives(cloudTestRepo.c_str()), 0); | ||||
| 	QCOMPARE(save_dives("./SampleDivesV3plus10local.ssrf"), 0); | ||||
| 	clear_dive_file_data(); | ||||
| 	// now pretend that we are online again and open the cloud storage and compare
 | ||||
| 	git_local_only = false; | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	QCOMPARE(save_dives("./SampleDivesV3plus10viacloud.ssrf"), 0); | ||||
| 	QFile org("./SampleDivesV3plus10local.ssrf"); | ||||
| 	org.open(QFile::ReadOnly); | ||||
|  | @ -260,10 +263,10 @@ void TestGitStorage::testGitStorageCloudOfflineSync() | |||
| 	QString written = outS.readAll(); | ||||
| 	QCOMPARE(readin, written); | ||||
| 	// write back out to cloud storage, move away the local cache, open again and compare
 | ||||
| 	QCOMPARE(save_dives(qPrintable(cloudTestRepo)), 0); | ||||
| 	QCOMPARE(save_dives(cloudTestRepo.c_str()), 0); | ||||
| 	clear_dive_file_data(); | ||||
| 	moveDir(localCacheDir, localCacheDir + "save"); | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	QCOMPARE(save_dives("./SampleDivesV3plus10fromcloud.ssrf"), 0); | ||||
| 	org.close(); | ||||
| 	org.open(QFile::ReadOnly); | ||||
|  | @ -292,10 +295,10 @@ void TestGitStorage::testGitStorageCloudMerge() | |||
| 
 | ||||
| 	// (1) open the repo, add dive test11 and save to the cloud
 | ||||
| 	git_local_only = false; | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test11.xml", &divelog), 0); | ||||
| 	process_loaded_dives(); | ||||
| 	QCOMPARE(save_dives(qPrintable(cloudTestRepo)), 0); | ||||
| 	QCOMPARE(save_dives(cloudTestRepo.c_str()), 0); | ||||
| 	clear_dive_file_data(); | ||||
| 
 | ||||
| 	// (2) switch to the second client by moving the old cache back in place
 | ||||
|  | @ -304,15 +307,15 @@ void TestGitStorage::testGitStorageCloudMerge() | |||
| 
 | ||||
| 	// (3) open the repo from the old cache and add dive test12 while offline
 | ||||
| 	git_local_only = true; | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test12.xml", &divelog), 0); | ||||
| 	process_loaded_dives(); | ||||
| 	QCOMPARE(save_dives(qPrintable(cloudTestRepo)), 0); | ||||
| 	QCOMPARE(save_dives(cloudTestRepo.c_str()), 0); | ||||
| 	clear_dive_file_data(); | ||||
| 
 | ||||
| 	// (4) now take things back online
 | ||||
| 	git_local_only = false; | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	clear_dive_file_data(); | ||||
| 
 | ||||
| 	// (5) now we should have all the dives in our repo on the second client
 | ||||
|  | @ -324,7 +327,7 @@ void TestGitStorage::testGitStorageCloudMerge() | |||
| 	QCOMPARE(save_dives("./SampleDivesV3plus10-11-12.ssrf"), 0); | ||||
| 	// then load from the cloud
 | ||||
| 	clear_dive_file_data(); | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	process_loaded_dives(); | ||||
| 	QCOMPARE(save_dives("./SampleDivesV3plus10-11-12-merged.ssrf"), 0); | ||||
| 	// finally compare what we have
 | ||||
|  | @ -341,7 +344,7 @@ void TestGitStorage::testGitStorageCloudMerge() | |||
| 
 | ||||
| 	// (6) move ourselves back to the first client and compare data there
 | ||||
| 	moveDir(localCacheDir + "client1", localCacheDir); | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	process_loaded_dives(); | ||||
| 	QCOMPARE(save_dives("./SampleDivesV3plus10-11-12-merged-client1.ssrf"), 0); | ||||
| 	QFile client1("./SampleDivesV3plus10-11-12-merged-client1.ssrf"); | ||||
|  | @ -357,13 +360,13 @@ void TestGitStorage::testGitStorageCloudMerge2() | |||
| 	// edit the same dive in the cloud repo
 | ||||
| 	// merge
 | ||||
| 	// (1) open repo, delete second dive, save offline
 | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	process_loaded_dives(); | ||||
| 	struct dive *dive = get_dive(1); | ||||
| 	delete_single_dive(1); | ||||
| 	QCOMPARE(save_dives("./SampleDivesMinus1.ssrf"), 0); | ||||
| 	git_local_only = true; | ||||
| 	QCOMPARE(save_dives(qPrintable(localCacheRepo)), 0); | ||||
| 	QCOMPARE(save_dives(localCacheRepo.c_str()), 0); | ||||
| 	git_local_only = false; | ||||
| 	clear_dive_file_data(); | ||||
| 
 | ||||
|  | @ -371,21 +374,21 @@ void TestGitStorage::testGitStorageCloudMerge2() | |||
| 	moveDir(localCacheDir, localCacheDir + "save"); | ||||
| 
 | ||||
| 	// (3) now we open the cloud storage repo and modify that second dive
 | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	process_loaded_dives(); | ||||
| 	dive = get_dive(1); | ||||
| 	QVERIFY(dive != NULL); | ||||
| 	free(dive->notes); | ||||
| 	dive->notes = strdup("These notes have been modified by TestGitStorage"); | ||||
| 	QCOMPARE(save_dives(qPrintable(cloudTestRepo)), 0); | ||||
| 	QCOMPARE(save_dives(cloudTestRepo.c_str()), 0); | ||||
| 	clear_dive_file_data(); | ||||
| 
 | ||||
| 	// (4) move the saved local cache  backinto place and try to open the cloud repo
 | ||||
| 	//     -> this forces a merge
 | ||||
| 	moveDir(localCacheDir + "save", localCacheDir); | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	QCOMPARE(save_dives("./SampleDivesMinus1-merged.ssrf"), 0); | ||||
| 	QCOMPARE(save_dives(qPrintable(cloudTestRepo)), 0); | ||||
| 	QCOMPARE(save_dives(cloudTestRepo.c_str()), 0); | ||||
| 	QFile org("./SampleDivesMinus1-merged.ssrf"); | ||||
| 	org.open(QFile::ReadOnly); | ||||
| 	QFile out("./SampleDivesMinus1.ssrf"); | ||||
|  | @ -406,7 +409,7 @@ void TestGitStorage::testGitStorageCloudMerge3() | |||
| 
 | ||||
| 
 | ||||
| 	// (1) open repo, edit notes of first three dives
 | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	process_loaded_dives(); | ||||
| 	struct dive *dive; | ||||
| 	QVERIFY((dive = get_dive(0)) != 0); | ||||
|  | @ -418,11 +421,11 @@ void TestGitStorage::testGitStorageCloudMerge3() | |||
| 	QVERIFY((dive = get_dive(2)) != 0); | ||||
| 	free(dive->notes); | ||||
| 	dive->notes = strdup("Create multi line dive notes\nLine 2\nLine 3\nLine 4\nLine 5\nThat should be enough"); | ||||
| 	QCOMPARE(save_dives(qPrintable(cloudTestRepo)), 0); | ||||
| 	QCOMPARE(save_dives(cloudTestRepo.c_str()), 0); | ||||
| 	clear_dive_file_data(); | ||||
| 
 | ||||
| 	// (2) make different edits offline
 | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	process_loaded_dives(); | ||||
| 	QVERIFY((dive = get_dive(0)) != 0); | ||||
| 	free(dive->notes); | ||||
|  | @ -434,14 +437,14 @@ void TestGitStorage::testGitStorageCloudMerge3() | |||
| 	free(dive->notes); | ||||
| 	dive->notes = strdup("single line dive notes"); | ||||
| 	git_local_only = true; | ||||
| 	QCOMPARE(save_dives(qPrintable(cloudTestRepo)), 0); | ||||
| 	QCOMPARE(save_dives(cloudTestRepo.c_str()), 0); | ||||
| 	git_local_only = false; | ||||
| 	clear_dive_file_data(); | ||||
| 
 | ||||
| 	// (3) simulate a second system by moving the cache away and open the cloud storage repo and modify
 | ||||
| 	//     those first dive notes differently while online
 | ||||
| 	moveDir(localCacheDir, localCacheDir + "save"); | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	process_loaded_dives(); | ||||
| 	QVERIFY((dive = get_dive(0)) != 0); | ||||
| 	free(dive->notes); | ||||
|  | @ -452,12 +455,12 @@ void TestGitStorage::testGitStorageCloudMerge3() | |||
| 	QVERIFY((dive = get_dive(2)) != 0); | ||||
| 	free(dive->notes); | ||||
| 	dive->notes = strdup("Line 2\nLine 3\nLine 4\nLine 5"); // keep the middle, remove first and last");
 | ||||
| 	QCOMPARE(save_dives(qPrintable(cloudTestRepo)), 0); | ||||
| 	QCOMPARE(save_dives(cloudTestRepo.c_str()), 0); | ||||
| 	clear_dive_file_data(); | ||||
| 
 | ||||
| 	// (4) move the saved local cache back into place and open the cloud repo -> this forces a merge
 | ||||
| 	moveDir(localCacheDir + "save", localCacheDir); | ||||
| 	QCOMPARE(parse_file(qPrintable(cloudTestRepo), &divelog), 0); | ||||
| 	QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0); | ||||
| 	QCOMPARE(save_dives("./SampleDivesMerge3.ssrf"), 0); | ||||
| 	// we are not trying to compare this to a pre-determined result... what this test
 | ||||
| 	// checks is that there are no parsing errors with the merge
 | ||||
|  |  | |||
|  | @ -42,8 +42,8 @@ void TestParsePerformance::initTestCase() | |||
| 	QNetworkProxy::setApplicationProxy(proxy); | ||||
| 
 | ||||
| 	// now cleanup the cache dir in case there's something weird from previous runs
 | ||||
| 	QString localCacheDir(get_local_dir(LARGE_TEST_REPO, "git")); | ||||
| 	QDir localCacheDirectory(localCacheDir); | ||||
| 	std::string localCacheDir = get_local_dir(LARGE_TEST_REPO, "git"); | ||||
| 	QDir localCacheDirectory(localCacheDir.c_str()); | ||||
| 	QCOMPARE(localCacheDirectory.removeRecursively(), true); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue