package com.door43.translationstudio.tasks; import android.os.Process; import com.door43.tools.reporting.Logger; import com.door43.translationstudio.AppContext; import com.door43.translationstudio.R; import com.door43.translationstudio.SettingsActivity; import com.door43.translationstudio.core.Profile; import com.door43.translationstudio.core.TargetTranslation; import com.door43.translationstudio.git.Repo; import com.door43.translationstudio.git.TransportCallback; import com.door43.util.tasks.ManagedTask; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.PushCommand; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.TransportException; import org.eclipse.jgit.errors.NoRemoteRepositoryException; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.transport.PushResult; import org.eclipse.jgit.transport.RemoteRefUpdate; import java.io.IOException; import java.util.Collection; /** * Pushes a target translation to the server */ public class PushTargetTranslationTask extends ManagedTask { public static final String TASK_ID = "push_target_translation_task"; private final TargetTranslation targetTranslation; private final boolean pushTags; private Status status = Status.UNKNOWN; private String message = ""; public PushTargetTranslationTask(TargetTranslation targetTranslation, boolean pushTags) { setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); this.targetTranslation = targetTranslation; this.pushTags = pushTags; } @Override public void start() { Profile profile = AppContext.getProfile(); if(AppContext.context().isNetworkAvailable() && profile != null && profile.gogsUser != null) { publishProgress(-1, "Uploading translation"); String server = AppContext.context().getUserPreferences().getString(SettingsActivity.KEY_PREF_GIT_SERVER, AppContext.context().getResources().getString(R.string.pref_default_git_server)); String remote = server + ":" + profile.gogsUser.getUsername() + "/" + this.targetTranslation.getId() + ".git"; try { this.targetTranslation.commitSync(); Repo repo = this.targetTranslation.getRepo(); this.message = push(repo, remote); } catch (Exception e) { e.printStackTrace(); } } } private String push(Repo repo, String remote) throws JGitInternalException { Git git; try { git = repo.getGit(); } catch (IOException e1) { return null; } // TODO: we might want to get some progress feedback for the user PushCommand pushCommand = git.push() .setTransportConfigCallback(new TransportCallback()) .setRemote(remote) .setProgressMonitor(new ProgressMonitor() { @Override public void start(int totalTasks) { } @Override public void beginTask(String title, int totalWork) { } @Override public void update(int completed) { } @Override public void endTask() { } @Override public boolean isCancelled() { return false; } }) .setForce(false) .setPushAll(); if(this.pushTags) { pushCommand.setPushTags(); } try { Iterable<PushResult> result = pushCommand.call(); StringBuffer response = new StringBuffer(); for (PushResult r : result) { Collection<RemoteRefUpdate> updates = r.getRemoteUpdates(); for (RemoteRefUpdate update : updates) { response.append(parseRemoteRefUpdate(update, remote)); } } // give back the response message this.status = Status.OK; return response.toString(); } catch (TransportException e) { Logger.e(this.getClass().getName(), e.getMessage(), e); Throwable cause = e.getCause(); if(cause != null) { Throwable subException = cause.getCause(); if(subException != null) { String detail = subException.getMessage(); if ("Auth fail".equals(detail)) { this.status = Status.AUTH_FAILURE; } } else if(cause instanceof NoRemoteRepositoryException) { this.status = Status.NO_REMOTE_REPO; } else if(cause.getMessage().contains("not permitted")) { this.status = Status.AUTH_FAILURE; } } return null; } catch (Exception e) { Logger.e(this.getClass().getName(), e.getMessage(), e); return null; } catch (OutOfMemoryError e) { Logger.e(this.getClass().getName(), e.getMessage(), e); this.status = Status.OUT_OF_MEMORY; return null; } catch (Throwable e) { Logger.e(this.getClass().getName(), e.getMessage(), e); return null; } } public Status getStatus() { return status; } public String getMessage() { return message; } public enum Status { OK, OUT_OF_MEMORY, AUTH_FAILURE, NO_REMOTE_REPO, UNKNOWN } /** * Parses the response from the remote * @param update * @return */ private String parseRemoteRefUpdate(RemoteRefUpdate update, String remote) { String msg = null; switch (update.getStatus()) { case AWAITING_REPORT: msg = String.format(AppContext.context().getResources().getString(R.string.git_awaiting_report), update.getRemoteName()); break; case NON_EXISTING: msg = String.format(AppContext.context().getResources().getString(R.string.git_non_existing), update.getRemoteName()); break; case NOT_ATTEMPTED: msg = String.format(AppContext.context().getResources().getString(R.string.git_not_attempted), update.getRemoteName()); break; case OK: msg = String.format(AppContext.context().getResources().getString(R.string.git_ok), update.getRemoteName()); break; case REJECTED_NODELETE: msg = String.format(AppContext.context().getResources().getString(R.string.git_rejected_nondelete), update.getRemoteName()); break; case REJECTED_NONFASTFORWARD: msg = String.format(AppContext.context().getResources().getString(R.string.git_rejected_nonfastforward), update.getRemoteName()); break; case REJECTED_OTHER_REASON: String reason = update.getMessage(); if (reason == null || reason.isEmpty()) { msg = String.format(AppContext.context().getResources().getString(R.string.git_rejected_other_reason), update.getRemoteName()); } else { msg = String.format(AppContext.context().getResources().getString(R.string.git_rejected_other_reason_detailed), update.getRemoteName(), reason); } break; case REJECTED_REMOTE_CHANGED: msg = String.format(AppContext.context().getResources().getString(R.string.git_rejected_remote_changed),update.getRemoteName()); break; case UP_TO_DATE: msg = String.format(AppContext.context().getResources().getString(R.string.git_uptodate), update.getRemoteName()); break; } msg += "\n" + String.format(AppContext.context().getResources().getString(R.string.git_server_details), remote); return msg; } }