diff --git a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/actions/CloneModelAction.java b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/actions/CloneModelAction.java index 95c79e8c..99148147 100644 --- a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/actions/CloneModelAction.java +++ b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/actions/CloneModelAction.java @@ -6,6 +6,7 @@ package org.archicontribs.modelrepository.actions; import java.io.File; +import java.net.URI; import java.security.GeneralSecurityException; import org.archicontribs.modelrepository.IModelRepositoryImages; @@ -22,6 +23,9 @@ import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.window.Window; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.SystemReader; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.progress.IProgressService; @@ -36,126 +40,141 @@ * 1. Check Primary Key * 2. Get user credentials * 3. Clone from Remote - * 4. If Grafico files exist load the model from the Grafico files and save it as temp file - * 5. If Grafico files do not exist create a new temp model and save it + * 4. If Grafico files exist load the model from the Grafico files and save it as temp file + * 5. If Grafico files do not exist create a new temp model and save it * 6. Store user credentials if prefs agree */ public class CloneModelAction extends AbstractModelAction { - - public CloneModelAction(IWorkbenchWindow window) { - super(window); - setImageDescriptor(IModelRepositoryImages.ImageFactory.getImageDescriptor(IModelRepositoryImages.ICON_CLONE)); - setText(Messages.CloneModelAction_0); - setToolTipText(Messages.CloneModelAction_0); - } - - @Override - public void run() { - // Check primary key set - try { - if(!EncryptedCredentialsStorage.checkPrimaryKeySet()) { - return; - } - } - catch(GeneralSecurityException ex) { - displayCredentialsErrorDialog(ex); - return; - } - catch(Exception ex) { - displayErrorDialog(Messages.CloneModelAction_0, ex); - return; - } - - CloneInputDialog dialog = new CloneInputDialog(fWindow.getShell()); - if(dialog.open() != Window.OK) { - return; - } - - final String repoURL = dialog.getURL(); - final boolean storeCredentials = dialog.doStoreCredentials(); - final UsernamePassword npw = dialog.getUsernamePassword(); - - if(!StringUtils.isSet(repoURL)) { - return; - } - - if(GraficoUtils.isHTTP(repoURL) && !StringUtils.isSet(npw.getUsername()) && npw.getPassword().length == 0) { - MessageDialog.openError(fWindow.getShell(), - Messages.CloneModelAction_0, - Messages.CloneModelAction_1); - return; - } - - // Create a new local folder - File localRepoFolder = GraficoUtils.getUniqueLocalFolder(ModelRepositoryPlugin.INSTANCE.getUserModelRepositoryFolder(), repoURL); - setRepository(new ArchiRepository(localRepoFolder)); - - try { - // Clone - Exception[] exception = new Exception[1]; - IProgressService ps = PlatformUI.getWorkbench().getProgressService(); - ps.busyCursorWhile(new IRunnableWithProgress() { - @Override - public void run(IProgressMonitor pm) { - try { - // Update Proxy - ProxyAuthenticator.update(); - - pm.beginTask(Messages.CloneModelAction_4, -1); - getRepository().cloneModel(repoURL, npw, new ProgressMonitorWrapper(pm)); - } - catch(Exception ex) { - exception[0] = ex; - } - finally { - // Clear Proxy - ProxyAuthenticator.clear(); - } - } - }); - - if(exception[0] != null) { - throw exception[0]; - } - - // Load it from the Grafico files if we can - IArchimateModel graficoModel = new GraficoModelLoader(getRepository()).loadModel(); - - // We couldn't load it from Grafico so create a new blank model - if(graficoModel == null) { - // New one. This will open in the tree - IArchimateModel model = IEditorModelManager.INSTANCE.createNewModel(); - model.setFile(getRepository().getTempModelFile()); - - // And Save it - IEditorModelManager.INSTANCE.saveModel(model); - - // Export to Grafico - getRepository().exportModelToGraficoFiles(); - - // And do a first commit - getRepository().commitChanges(Messages.CloneModelAction_3, false); - - // Save the checksum - getRepository().saveChecksum(); - } - - // Store repo credentials if HTTP and option is set - if(GraficoUtils.isHTTP(repoURL) && storeCredentials) { - EncryptedCredentialsStorage cs = EncryptedCredentialsStorage.forRepository(getRepository()); - cs.store(npw); - } - - // Notify listeners - notifyChangeListeners(IRepositoryListener.REPOSITORY_ADDED); - } - catch(Exception ex) { - displayErrorDialog(Messages.CloneModelAction_0, ex); - } - } - - @Override - protected boolean shouldBeEnabled() { - return true; - } + + public CloneModelAction(IWorkbenchWindow window) { + super(window); + setImageDescriptor(IModelRepositoryImages.ImageFactory.getImageDescriptor(IModelRepositoryImages.ICON_CLONE)); + setText(Messages.CloneModelAction_0); + setToolTipText(Messages.CloneModelAction_0); + } + + @Override + public void run() { + // Check primary key set + try { + if (!EncryptedCredentialsStorage.checkPrimaryKeySet()) { + return; + } + } catch (GeneralSecurityException ex) { + displayCredentialsErrorDialog(ex); + return; + } catch (Exception ex) { + displayErrorDialog(Messages.CloneModelAction_0, ex); + return; + } + + CloneInputDialog dialog = new CloneInputDialog(fWindow.getShell()); + if (dialog.open() != Window.OK) { + return; + } + + final String repoURL = dialog.getURL(); + final boolean storeCredentials = dialog.doStoreCredentials(); + final UsernamePassword npw = dialog.getUsernamePassword(); + final boolean skipSSLVerification = dialog.skipSSLverification(); + + if (!StringUtils.isSet(repoURL)) { + return; + } + + if (GraficoUtils.isHTTP(repoURL) && !StringUtils.isSet(npw.getUsername()) && npw.getPassword().length == 0) { + MessageDialog.openError(fWindow.getShell(), Messages.CloneModelAction_0, Messages.CloneModelAction_1); + return; + } + + // Create a new local folder + File localRepoFolder = GraficoUtils + .getUniqueLocalFolder(ModelRepositoryPlugin.INSTANCE.getUserModelRepositoryFolder(), repoURL); + setRepository(new ArchiRepository(localRepoFolder)); + + if (skipSSLVerification) + disableSSLVerify(repoURL); + try { + // Clone + Exception[] exception = new Exception[1]; + IProgressService ps = PlatformUI.getWorkbench().getProgressService(); + ps.busyCursorWhile(new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor pm) { + try { + // Update Proxy + ProxyAuthenticator.update(); + + pm.beginTask(Messages.CloneModelAction_4, -1); + getRepository().cloneModel(repoURL, npw, new ProgressMonitorWrapper(pm)); + } catch (Exception ex) { + exception[0] = ex; + } finally { + // Clear Proxy + ProxyAuthenticator.clear(); + } + } + }); + + if (exception[0] != null) { + throw exception[0]; + } + + // Load it from the Grafico files if we can + IArchimateModel graficoModel = new GraficoModelLoader(getRepository()).loadModel(); + + // We couldn't load it from Grafico so create a new blank model + if (graficoModel == null) { + // New one. This will open in the tree + IArchimateModel model = IEditorModelManager.INSTANCE.createNewModel(); + model.setFile(getRepository().getTempModelFile()); + + // And Save it + IEditorModelManager.INSTANCE.saveModel(model); + + // Export to Grafico + getRepository().exportModelToGraficoFiles(); + + // And do a first commit + getRepository().commitChanges(Messages.CloneModelAction_3, false); + + // Save the checksum + getRepository().saveChecksum(); + } + + // Store repo credentials if HTTP and option is set + if (GraficoUtils.isHTTP(repoURL) && storeCredentials) { + EncryptedCredentialsStorage cs = EncryptedCredentialsStorage.forRepository(getRepository()); + cs.store(npw); + } + + // Notify listeners + notifyChangeListeners(IRepositoryListener.REPOSITORY_ADDED); + } catch (Exception ex) { + displayErrorDialog(Messages.CloneModelAction_0, ex); + } + } + + private void disableSSLVerify(String repoURL) { + try { + + URI gitServer = new URI(repoURL); + if (gitServer.getScheme().equals("https")) { + FileBasedConfig config = SystemReader.getInstance().openUserConfig(null, FS.DETECTED); + synchronized (config) { + config.load(); + config.setBoolean("http", "https://" + gitServer.getHost() + ':' + + (gitServer.getPort() == -1 ? 443 : gitServer.getPort()), "sslVerify", false); + config.save(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + protected boolean shouldBeEnabled() { + return true; + } } diff --git a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/CloneInputDialog.java b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/CloneInputDialog.java index 7ec9666b..640bcb83 100644 --- a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/CloneInputDialog.java +++ b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/CloneInputDialog.java @@ -38,11 +38,13 @@ public class CloneInputDialog extends TitleAreaDialog { private Text txtPassword; private Button storeCredentialsButton; + private Button skipSSLButton; private String URL; private String username; private char[] password; private boolean doStoreCredentials; + private boolean skipSSLVerification; public CloneInputDialog(Shell parentShell) { super(parentShell); @@ -82,6 +84,10 @@ public void modifyText(ModifyEvent e) { txtPassword = createTextField(container, Messages.CloneInputDialog_4, SWT.PASSWORD); createPreferenceButton(container); + skipSSLButton = new Button(container, SWT.CHECK); + skipSSLButton.setText(Messages.CloneInputDialog_btnCheckButton_text); + new Label(container, SWT.NONE); + return area; } @@ -116,6 +122,7 @@ protected void saveInput() { password = txtPassword.getTextChars(); URL = txtURL.getText().trim(); doStoreCredentials = storeCredentialsButton.getSelection(); + skipSSLVerification=skipSSLButton.getSelection(); } @Override @@ -123,6 +130,9 @@ protected void okPressed() { saveInput(); super.okPressed(); } + public boolean skipSSLverification() { + return skipSSLVerification; + } public UsernamePassword getUsernamePassword() { return new UsernamePassword(username, password); @@ -135,4 +145,5 @@ public String getURL() { public boolean doStoreCredentials() { return doStoreCredentials; } + } \ No newline at end of file diff --git a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/Messages.java b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/Messages.java index 70342eb6..742046be 100644 --- a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/Messages.java +++ b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/Messages.java @@ -115,6 +115,7 @@ public class Messages extends NLS { public static String UserNamePasswordDialog_5; public static String UserNamePasswordDialog_6; + public static String CloneInputDialog_btnCheckButton_text; static { // initialize resource bundle NLS.initializeMessages(BUNDLE_NAME, Messages.class); diff --git a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/messages.properties b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/messages.properties index f27935e7..44230fa4 100644 --- a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/messages.properties +++ b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/dialogs/messages.properties @@ -1,55 +1,58 @@ +#Eclipse modern messages class +#Thu Mar 25 21:24:10 CET 2021 +UserNamePasswordDialog_6=There was an error\: +NewPrimaryPasswordDialog_21=New password must have a minimum of +SwitchBranchDialog_2=Branch\: +NewPrimaryPasswordDialog_20={0} special characters, +SwitchBranchDialog_1=Select the branch to switch to. +SwitchBranchDialog_0=Switch Branch +UserNamePasswordDialog_1=Enter user name and password +UserNamePasswordDialog_0=Credentials +UserNamePasswordDialog_3=Password\: +NewPrimaryPasswordDialog_19={0} digits, +UserNamePasswordDialog_2=User Name\: +NewPrimaryPasswordDialog_18={0} upper case, +UserNamePasswordDialog_5=Error saving credentials +NewPrimaryPasswordDialog_17={0} lower case, +UserNamePasswordDialog_4=Store user name and password +NewPrimaryPasswordDialog_16={0} characters, +NewPrimaryPasswordDialog_15=Must have a minimum of {0} special characters +NewPrimaryPasswordDialog_14=Must have a minimum of {0} digits +NewPrimaryPasswordDialog_13=Must have a minimum of {0} upper-case characters +NewPrimaryPasswordDialog_12=Must have a minimum of {0} lower-case characters +NewPrimaryPasswordDialog_11=Must be a minimum of {0} characters +NewPrimaryPasswordDialog_10=Could not set password\: +PrimaryPasswordDialog_1=Enter Primary Password +PrimaryPasswordDialog_0=Primary Password +AddBranchDialog_2=Enter the name of the local branch to create. +AddBranchDialog_3=Branch\: AddBranchDialog_0=Add Branch to current commit AddBranchDialog_1=Add Branch -AddBranchDialog_2=Enter the name of the local branch to create. -AddBranchDialog_3=Branch: -AddBranchDialog_4=The branch name must not end or start with a dot. -AddBranchDialog_5=The branch name must not end or start with a slash. +CommitDialog_3=User Email\: +CommitDialog_2=User Name\: +CommitDialog_1=Please enter user details and a commit message +CommitDialog_0=Commit +CommitDialog_6=Repository\: +CommitDialog_5=Amend last commit instead of creating new one +CommitDialog_4=Commit message\: AddBranchDialog_6=Add Branch && Checkout AddBranchDialog_7=Invalid character sequence in branch name. +AddBranchDialog_4=The branch name must not end or start with a dot. +AddBranchDialog_5=The branch name must not end or start with a slash. +NewModelRepoDialog_0=New Model Repository +CloneInputDialog_2=URL\: +CloneInputDialog_3=User Name\: +CloneInputDialog_4=Password\: CloneInputDialog_0=Add Remote Model CloneInputDialog_1=Please enter the URL of the remote model and user credentials (if using HTTP) -CloneInputDialog_2=URL: -CloneInputDialog_3=User Name: -CloneInputDialog_4=Password: -CommitDialog_0=Commit -CommitDialog_1=Please enter user details and a commit message -CommitDialog_2=User Name: -CommitDialog_3=User Email: -CommitDialog_4=Commit message: -CommitDialog_5=Amend last commit instead of creating new one -CommitDialog_6=Repository: -NewModelRepoDialog_0=New Model Repository -NewPrimaryPasswordDialog_0=Primary Password -NewPrimaryPasswordDialog_1=Change or create a new primary password. This primary password is used to access an encryption key that secures repository credentials. -NewPrimaryPasswordDialog_10=Could not set password: -NewPrimaryPasswordDialog_11=Must be a minimum of {0} characters -NewPrimaryPasswordDialog_12=Must have a minimum of {0} lower-case characters -NewPrimaryPasswordDialog_13=Must have a minimum of {0} upper-case characters -NewPrimaryPasswordDialog_14=Must have a minimum of {0} digits -NewPrimaryPasswordDialog_15=Must have a minimum of {0} special characters -NewPrimaryPasswordDialog_16={0} characters, -NewPrimaryPasswordDialog_17={0} lower case, -NewPrimaryPasswordDialog_18={0} upper case, -NewPrimaryPasswordDialog_19={0} digits, -NewPrimaryPasswordDialog_2=The passwords do not match -NewPrimaryPasswordDialog_20={0} special characters, -NewPrimaryPasswordDialog_21=New password must have a minimum of -NewPrimaryPasswordDialog_3=New Primary Password: -NewPrimaryPasswordDialog_4=Retype Primary Password: -NewPrimaryPasswordDialog_5=Change primary password and keep current encryption key +CloneInputDialog_btnCheckButton_text=Skip SSL Handshake verification +NewPrimaryPasswordDialog_8=Current Primary Password\: +NewPrimaryPasswordDialog_9=Could not set password. The current password may be incorrect. NewPrimaryPasswordDialog_6=Set new primary password and generate new encryption key NewPrimaryPasswordDialog_7=When setting a new primary password, all stored passwords will be lost and need to be re-entered for each repository\! -NewPrimaryPasswordDialog_8=Current Primary Password: -NewPrimaryPasswordDialog_9=Could not set password. The current password may be incorrect. -PrimaryPasswordDialog_0=Primary Password -PrimaryPasswordDialog_1=Enter Primary Password -SwitchBranchDialog_0=Switch Branch -SwitchBranchDialog_1=Select the branch to switch to. -SwitchBranchDialog_2=Branch: -UserNamePasswordDialog_0=Credentials -UserNamePasswordDialog_1=Enter user name and password -UserNamePasswordDialog_2=User Name: -UserNamePasswordDialog_3=Password: -UserNamePasswordDialog_4=Store user name and password -UserNamePasswordDialog_5=Error saving credentials -UserNamePasswordDialog_6=There was an error: +NewPrimaryPasswordDialog_4=Retype Primary Password\: +NewPrimaryPasswordDialog_5=Change primary password and keep current encryption key +NewPrimaryPasswordDialog_2=The passwords do not match +NewPrimaryPasswordDialog_3=New Primary Password\: +NewPrimaryPasswordDialog_0=Primary Password +NewPrimaryPasswordDialog_1=Change or create a new primary password. This primary password is used to access an encryption key that secures repository credentials. diff --git a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/grafico/ArchiRepository.java b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/grafico/ArchiRepository.java index ca002bb3..63e7259e 100644 --- a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/grafico/ArchiRepository.java +++ b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/grafico/ArchiRepository.java @@ -63,533 +63,546 @@ import com.archimatetool.model.IArchimateModel; /** - * Representation of a local repository - * This is a wrapper class around a local repo folder + * Representation of a local repository This is a wrapper class around a local + * repo folder * * @author Phillip Beauvoir */ public class ArchiRepository implements IArchiRepository { - - /** - * The folder location of the local repository - */ - private File fLocalRepoFolder; - - public ArchiRepository(File localRepoFolder) { - fLocalRepoFolder = localRepoFolder; - } - - @Override - public File getLocalRepositoryFolder() { - return fLocalRepoFolder; - } - - @Override - public File getLocalGitFolder() { - return new File(getLocalRepositoryFolder(), ".git"); //$NON-NLS-1$ - } - - @Override - public String getName() { - String[] result = new String[1]; - - // Find the "folder.xml" file and read it from there - File file = new File(getLocalRepositoryFolder(), IGraficoConstants.MODEL_FOLDER + "/" + IGraficoConstants.FOLDER_XML); //$NON-NLS-1$ - if(file.exists()) { - try(Stream stream = Files.lines(Paths.get(file.getAbsolutePath()))) { - stream.forEach(s -> { - if(result[0] == null && s.indexOf("name=") != -1) { //$NON-NLS-1$ - String segments[] = s.split("\""); //$NON-NLS-1$ - if(segments.length == 2) { - result[0] = segments[1]; - } - } - }); - } - catch(IOException ex) { - ex.printStackTrace(); - } - } - - return result[0] != null ? result[0] : fLocalRepoFolder.getName(); - } - - @Override - public File getTempModelFile() { - return new File(getLocalRepositoryFolder(), "/.git/" + IGraficoConstants.LOCAL_ARCHI_FILENAME); //$NON-NLS-1$ - } - - @Override - public String getOnlineRepositoryURL() throws IOException { - try(Git git = Git.open(getLocalRepositoryFolder())) { - return git.getRepository().getConfig().getString("remote", IGraficoConstants.ORIGIN, "url"); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - @Override - public IArchimateModel locateModel() { - File tempFile = getTempModelFile(); - - for(IArchimateModel model : IEditorModelManager.INSTANCE.getModels()) { - if(tempFile.equals(model.getFile())) { - return model; - } - } - - return null; - } - - @Override - public boolean hasChangesToCommit() throws IOException, GitAPIException { - try(Git git = Git.open(getLocalRepositoryFolder())) { - Status status = git.status().call(); - return !status.isClean(); - } - } - - @Override - public RevCommit commitChanges(String commitMessage, boolean amend) throws GitAPIException, IOException { - try(Git git = Git.open(getLocalRepositoryFolder())) { - Status status = git.status().call(); - - // Nothing changed - if(status.isClean()) { - return null; - } - - // Check lock file is deleted - checkDeleteLockFile(); - - // Add modified files to index - AddCommand addCommand = git.add(); - addCommand.addFilepattern("."); //$NON-NLS-1$ - addCommand.setUpdate(false); - addCommand.call(); - - // Add missing files to index - for(String s : status.getMissing()) { - git.rm().addFilepattern(s).call(); - } - - // Commit - CommitCommand commitCommand = git.commit(); - PersonIdent userDetails = getUserDetails(); - commitCommand.setAuthor(userDetails); - commitCommand.setMessage(commitMessage); - commitCommand.setAmend(amend); - return commitCommand.call(); - } - } - - @Override - public void cloneModel(String repoURL, UsernamePassword npw, ProgressMonitor monitor) throws GitAPIException, IOException { - CloneCommand cloneCommand = Git.cloneRepository(); - cloneCommand.setDirectory(getLocalRepositoryFolder()); - cloneCommand.setURI(repoURL); - cloneCommand.setTransportConfigCallback(CredentialsAuthenticator.getTransportConfigCallback(repoURL, npw)); - cloneCommand.setProgressMonitor(monitor); - - try(Git git = cloneCommand.call()) { - setDefaultConfigSettings(git.getRepository()); - } - } - - @Override - public Iterable pushToRemote(UsernamePassword npw, ProgressMonitor monitor) throws IOException, GitAPIException { - try(Git git = Git.open(getLocalRepositoryFolder())) { - PushCommand pushCommand = git.push(); - pushCommand.setTransportConfigCallback(CredentialsAuthenticator.getTransportConfigCallback(getOnlineRepositoryURL(), npw)); - pushCommand.setProgressMonitor(monitor); - - Iterable result = pushCommand.call(); - - // After a successful push, ensure we are tracking the current branch - setTrackedBranch(git.getRepository(), git.getRepository().getBranch()); - - return result; - } - } - - @Override - public PullResult pullFromRemote(UsernamePassword npw, ProgressMonitor monitor) throws IOException, GitAPIException { - try(Git git = Git.open(getLocalRepositoryFolder())) { - PullCommand pullCommand = git.pull(); - pullCommand.setTransportConfigCallback(CredentialsAuthenticator.getTransportConfigCallback(getOnlineRepositoryURL(), npw)); - pullCommand.setRebase(false); // Merge, not rebase - pullCommand.setProgressMonitor(monitor); - return pullCommand.call(); - } - } - - @Override - public FetchResult fetchFromRemote(UsernamePassword npw, ProgressMonitor monitor, boolean isDryrun) throws IOException, GitAPIException { - try(Git git = Git.open(getLocalRepositoryFolder())) { - // Check and set tracked master branch - setTrackedBranch(git.getRepository(), IGraficoConstants.MASTER); - FetchCommand fetchCommand = git.fetch(); - fetchCommand.setTransportConfigCallback(CredentialsAuthenticator.getTransportConfigCallback(getOnlineRepositoryURL(), npw)); - fetchCommand.setProgressMonitor(monitor); - fetchCommand.setDryRun(isDryrun); - return fetchCommand.call(); - } - } - - @Override - public Git createNewLocalGitRepository(String URL) throws GitAPIException, IOException, URISyntaxException { - if(getLocalRepositoryFolder().exists() && getLocalRepositoryFolder().list().length > 0) { - throw new IOException("Directory: " + getLocalRepositoryFolder().getAbsolutePath() + " is not empty."); //$NON-NLS-1$ //$NON-NLS-2$ - } - - InitCommand initCommand = Git.init(); - initCommand.setDirectory(getLocalRepositoryFolder()); - Git git = initCommand.call(); - - RemoteAddCommand remoteAddCommand = git.remoteAdd(); - remoteAddCommand.setName(IGraficoConstants.ORIGIN); - remoteAddCommand.setUri(new URIish(URL)); - remoteAddCommand.call(); - - setDefaultConfigSettings(git.getRepository()); - - // Set tracked master branch - setTrackedBranch(git.getRepository(), IGraficoConstants.MASTER); - - return git; - } - - @Override - public byte[] getFileContents(String path, String ref) throws IOException { - byte[] bytes = null; - - try(Repository repository = Git.open(getLocalRepositoryFolder()).getRepository()) { - ObjectId lastCommitId = repository.resolve(ref); - - try(RevWalk revWalk = new RevWalk(repository)) { - RevCommit commit = revWalk.parseCommit(lastCommitId); - RevTree tree = commit.getTree(); - - // now try to find a specific file - try(TreeWalk treeWalk = new TreeWalk(repository)) { - treeWalk.addTree(tree); - treeWalk.setRecursive(true); - treeWalk.setFilter(PathFilter.create(path)); - - // Not found, return null - if(!treeWalk.next()) { - return null; - } - - ObjectId objectId = treeWalk.getObjectId(0); - ObjectLoader loader = repository.open(objectId); - - bytes = loader.getBytes(); - } - - revWalk.dispose(); - } - } - - return bytes; - } - - @Override - public String getWorkingTreeFileContents(String path) throws IOException { - String str = ""; //$NON-NLS-1$ - - try(Git git = Git.open(getLocalRepositoryFolder())) { - try(BufferedReader in = new BufferedReader(new FileReader(new File(getLocalRepositoryFolder(), path)))) { - String line; - while((line = in.readLine()) != null) { - str += line + "\n"; //$NON-NLS-1$ - } - } - } - - return str; - } - - @Override - public void resetToRef(String ref) throws IOException, GitAPIException { - // Check lock file is deleted - checkDeleteLockFile(); - - try(Git git = Git.open(getLocalRepositoryFolder())) { - // Reset to master - ResetCommand resetCommand = git.reset(); - resetCommand.setRef(ref); - resetCommand.setMode(ResetType.HARD); - resetCommand.call(); - - // Clean extra files - CleanCommand cleanCommand = git.clean(); - cleanCommand.setCleanDirectories(true); - cleanCommand.call(); - } - } - - @Override - public boolean isHeadAndRemoteSame() throws IOException, GitAPIException { - try(Repository repository = Git.open(getLocalRepositoryFolder()).getRepository()) { - // Get remote branch ref - BranchInfo currentRemoteBranch = getBranchStatus().getCurrentRemoteBranch(); - if(currentRemoteBranch == null) { - return false; - } - - // Remote - Ref remoteRef = currentRemoteBranch.getRef(); - - // Head - Ref headRef = repository.findRef(HEAD); - - // In case of missing ref return false - if(headRef == null || remoteRef == null) { - return false; - } - - return headRef.getObjectId().equals(remoteRef.getObjectId()); - } - } - - @Override - public void exportModelToGraficoFiles() throws IOException, GitAPIException { - // Open the model before showing the progress monitor - IArchimateModel model = IEditorModelManager.INSTANCE.openModel(getTempModelFile()); - - if(model == null) { - throw new IOException(Messages.ArchiRepository_0); - } - - final Exception[] exception = new Exception[1]; - - try { - // When using this be careful that no UI operations are called as this could lead to an SWT Invalid thread access exception - // This will show a Cancel button which will not cancel, but this progress monitor is the only one which does not freeze the UI - PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() { - @Override - public void run(IProgressMonitor pm) { - pm.beginTask(Messages.ArchiRepository_1, IProgressMonitor.UNKNOWN); - - try { - // Export - GraficoModelExporter exporter = new GraficoModelExporter(model, getLocalRepositoryFolder()); - exporter.exportModel(); - - // Check lock file is deleted - checkDeleteLockFile(); - - // Stage modified files to index - this can take a long time! - // This will clear any different line endings and calls to git.status() will be faster - try(Git git = Git.open(getLocalRepositoryFolder())) { - AddCommand addCommand = git.add(); - addCommand.addFilepattern("."); //$NON-NLS-1$ - addCommand.setUpdate(false); - addCommand.call(); - } - } - catch(IOException | GitAPIException ex) { - exception[0] = ex; - } - } - }); - } - catch(InvocationTargetException | InterruptedException ex) { - throw new IOException(ex); - } - - if(exception[0] instanceof IOException) { - throw (IOException)exception[0]; - } - if(exception[0] instanceof GitAPIException) { - throw (GitAPIException)exception[0]; - } - } - - @Override - public PersonIdent getUserDetails() throws IOException { - try(Git git = Git.open(getLocalRepositoryFolder())) { - StoredConfig config = git.getRepository().getConfig(); - String name = StringUtils.safeString(config.getString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_NAME)); - String email = StringUtils.safeString(config.getString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_EMAIL)); - return new PersonIdent(name, email); - } - } - - @Override - public void saveUserDetails(String name, String email) throws IOException { - // Get global user details from .gitconfig for comparison - PersonIdent global = new PersonIdent("", ""); //$NON-NLS-1$ //$NON-NLS-2$ - - try { - global = GraficoUtils.getGitConfigUserDetails(); - } - catch(ConfigInvalidException ex) { - ex.printStackTrace(); - } - - // Save to local config - try(Git git = Git.open(getLocalRepositoryFolder())) { - StoredConfig config = git.getRepository().getConfig(); - - // If global name == local name or blank then unset - if(!StringUtils.isSet(name) || global.getName().equals(name)) { - config.unset(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_NAME); - } - // Set - else { - config.setString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_NAME, name); - } - - // If global email == local email or blank then unset - if(!StringUtils.isSet(email) || global.getEmailAddress().equals(email)) { - config.unset(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_EMAIL); - } - else { - config.setString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_EMAIL, email); - } - - config.save(); - } - } - - @Override - public boolean equals(Object obj) { - if((obj != null) && (obj instanceof ArchiRepository)) { - return fLocalRepoFolder != null && fLocalRepoFolder.equals(((IArchiRepository)obj).getLocalRepositoryFolder()); - } - return false; - } - - /** - * Set default settings in the config file - * @param repository - * @throws IOException - */ - private void setDefaultConfigSettings(Repository repository) throws IOException { - StoredConfig config = repository.getConfig(); - - /* - * Set Line endings in the config file to autocrlf=input - * This ensures that files are not seen as different - */ - config.setString(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_AUTOCRLF, "input"); //$NON-NLS-1$ - - /* - * Set longpaths=true because garbage collection is not possible otherwise - * See https://stackoverflow.com/questions/22575662/filename-too-long-in-git-for-windows - */ - config.setString(ConfigConstants.CONFIG_CORE_SECTION, null, "longpaths", "true"); //$NON-NLS-1$ //$NON-NLS-2$ - - config.save(); - } - - /** - * Set the given branchName to track "origin" - */ - private void setTrackedBranch(Repository repository, String branchName) throws IOException { - if(branchName == null) { - return; - } - - StoredConfig config = repository.getConfig(); - - if(!IGraficoConstants.ORIGIN.equals(config.getString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_REMOTE))) { - config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_REMOTE, IGraficoConstants.ORIGIN); - config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_MERGE, Constants.R_HEADS + branchName); - config.save(); - } - } - - - @Override - public boolean hasLocalChanges() throws IOException { - String latestChecksum = getLatestChecksum(); - if(latestChecksum == null) { - return false; - } - - String currentChecksum = createChecksum(); - return !latestChecksum.equals(currentChecksum); - } - - @Override - public boolean saveChecksum() throws IOException { - // Get the file's checksum as string - String checksum = createChecksum(); - if(checksum == null) { - return false; - } - - File checksumFile = new File(getLocalGitFolder(), "checksum"); //$NON-NLS-1$ - Files.write(Paths.get(checksumFile.getAbsolutePath()), checksum.getBytes(), StandardOpenOption.CREATE); - - return true; - } - - @Override - public BranchStatus getBranchStatus() throws IOException, GitAPIException { - return new BranchStatus(this); - } - - private String getLatestChecksum() throws IOException { - File checksumFile = new File(getLocalGitFolder(), "checksum"); //$NON-NLS-1$ - if(!checksumFile.exists()) { - return null; - } - - byte[] bytes = Files.readAllBytes(Paths.get(checksumFile.getAbsolutePath())); - return new String(bytes); - } - - private String createChecksum() throws IOException { - File tempFile = getTempModelFile(); - - if(tempFile == null) { - return null; - } - - MessageDigest digest = null; - try { - digest = MessageDigest.getInstance("MD5"); //$NON-NLS-1$ - } - catch(NoSuchAlgorithmException ex) { - throw new IOException("NoSuchAlgorithm Exception", ex); //$NON-NLS-1$ - } - - // Get file input stream for reading the file content - FileInputStream fis = new FileInputStream(tempFile); - - // Create byte array to read data in chunks - byte[] byteArray = new byte[1024]; - int bytesCount = 0; - - // Read file data and update in message digest - while((bytesCount = fis.read(byteArray)) != -1) { - digest.update(byteArray, 0, bytesCount); - } - - fis.close(); - - // Get the hash's bytes - byte[] bytes = digest.digest(); - - // This bytes[] has bytes in decimal format; - // Convert it to hexadecimal format - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < bytes.length; i++) { - sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1)); - } - - return sb.toString(); - } - - /** - * In some cases the lock file exists and leads to an error, so we delete it - */ - private void checkDeleteLockFile() { - File lockFile = new File(getLocalGitFolder(), "index.lock"); //$NON-NLS-1$ - if(lockFile.exists() && lockFile.canWrite()) { - lockFile.delete(); - } - } + + /** + * The folder location of the local repository + */ + private File fLocalRepoFolder; + + public ArchiRepository(File localRepoFolder) { + fLocalRepoFolder = localRepoFolder; + } + + @Override + public File getLocalRepositoryFolder() { + return fLocalRepoFolder; + } + + @Override + public File getLocalGitFolder() { + return new File(getLocalRepositoryFolder(), ".git"); //$NON-NLS-1$ + } + + @Override + public String getName() { + String[] result = new String[1]; + + // Find the "folder.xml" file and read it from there + File file = new File(getLocalRepositoryFolder(), + IGraficoConstants.MODEL_FOLDER + "/" + IGraficoConstants.FOLDER_XML); //$NON-NLS-1$ + if (file.exists()) { + try (Stream stream = Files.lines(Paths.get(file.getAbsolutePath()))) { + stream.forEach(s -> { + if (result[0] == null && s.indexOf("name=") != -1) { //$NON-NLS-1$ + String segments[] = s.split("\""); //$NON-NLS-1$ + if (segments.length == 2) { + result[0] = segments[1]; + } + } + }); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + return result[0] != null ? result[0] : fLocalRepoFolder.getName(); + } + + @Override + public File getTempModelFile() { + return new File(getLocalRepositoryFolder(), "/.git/" + IGraficoConstants.LOCAL_ARCHI_FILENAME); //$NON-NLS-1$ + } + + @Override + public String getOnlineRepositoryURL() throws IOException { + try (Git git = Git.open(getLocalRepositoryFolder())) { + return git.getRepository().getConfig().getString("remote", IGraficoConstants.ORIGIN, "url"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + @Override + public IArchimateModel locateModel() { + File tempFile = getTempModelFile(); + + for (IArchimateModel model : IEditorModelManager.INSTANCE.getModels()) { + if (tempFile.equals(model.getFile())) { + return model; + } + } + + return null; + } + + @Override + public boolean hasChangesToCommit() throws IOException, GitAPIException { + try (Git git = Git.open(getLocalRepositoryFolder())) { + Status status = git.status().call(); + return !status.isClean(); + } + } + + @Override + public RevCommit commitChanges(String commitMessage, boolean amend) throws GitAPIException, IOException { + try (Git git = Git.open(getLocalRepositoryFolder())) { + Status status = git.status().call(); + + // Nothing changed + if (status.isClean()) { + return null; + } + + // Check lock file is deleted + checkDeleteLockFile(); + + // Add modified files to index + AddCommand addCommand = git.add(); + addCommand.addFilepattern("."); //$NON-NLS-1$ + addCommand.setUpdate(false); + addCommand.call(); + + // Add missing files to index + for (String s : status.getMissing()) { + git.rm().addFilepattern(s).call(); + } + + // Commit + CommitCommand commitCommand = git.commit(); + PersonIdent userDetails = getUserDetails(); + commitCommand.setAuthor(userDetails); + commitCommand.setMessage(commitMessage); + commitCommand.setAmend(amend); + return commitCommand.call(); + } + } + + @Override + public void cloneModel(String repoURL, UsernamePassword npw, ProgressMonitor monitor) + throws GitAPIException, IOException { + + CloneCommand cloneCommand = Git.cloneRepository(); + cloneCommand.setDirectory(getLocalRepositoryFolder()); + cloneCommand.setURI(repoURL); + cloneCommand.setTransportConfigCallback(CredentialsAuthenticator.getTransportConfigCallback(repoURL, npw)); + cloneCommand.setProgressMonitor(monitor); + + try (Git git = cloneCommand.call()) { + setDefaultConfigSettings(git.getRepository()); + } + } + + @Override + public Iterable pushToRemote(UsernamePassword npw, ProgressMonitor monitor) + throws IOException, GitAPIException { + try (Git git = Git.open(getLocalRepositoryFolder())) { + PushCommand pushCommand = git.push(); + pushCommand.setTransportConfigCallback( + CredentialsAuthenticator.getTransportConfigCallback(getOnlineRepositoryURL(), npw)); + pushCommand.setProgressMonitor(monitor); + + Iterable result = pushCommand.call(); + + // After a successful push, ensure we are tracking the current branch + setTrackedBranch(git.getRepository(), git.getRepository().getBranch()); + + return result; + } + } + + @Override + public PullResult pullFromRemote(UsernamePassword npw, ProgressMonitor monitor) + throws IOException, GitAPIException { + try (Git git = Git.open(getLocalRepositoryFolder())) { + PullCommand pullCommand = git.pull(); + pullCommand.setTransportConfigCallback( + CredentialsAuthenticator.getTransportConfigCallback(getOnlineRepositoryURL(), npw)); + pullCommand.setRebase(false); // Merge, not rebase + pullCommand.setProgressMonitor(monitor); + return pullCommand.call(); + } + } + + @Override + public FetchResult fetchFromRemote(UsernamePassword npw, ProgressMonitor monitor, boolean isDryrun) + throws IOException, GitAPIException { + try (Git git = Git.open(getLocalRepositoryFolder())) { + // Check and set tracked master branch + setTrackedBranch(git.getRepository(), IGraficoConstants.MASTER); + FetchCommand fetchCommand = git.fetch(); + fetchCommand.setTransportConfigCallback( + CredentialsAuthenticator.getTransportConfigCallback(getOnlineRepositoryURL(), npw)); + fetchCommand.setProgressMonitor(monitor); + fetchCommand.setDryRun(isDryrun); + return fetchCommand.call(); + } + } + + @Override + public Git createNewLocalGitRepository(String URL) throws GitAPIException, IOException, URISyntaxException { + if (getLocalRepositoryFolder().exists() && getLocalRepositoryFolder().list().length > 0) { + throw new IOException("Directory: " + getLocalRepositoryFolder().getAbsolutePath() + " is not empty."); //$NON-NLS-1$ //$NON-NLS-2$ + } + + InitCommand initCommand = Git.init(); + initCommand.setDirectory(getLocalRepositoryFolder()); + Git git = initCommand.call(); + + RemoteAddCommand remoteAddCommand = git.remoteAdd(); + remoteAddCommand.setName(IGraficoConstants.ORIGIN); + remoteAddCommand.setUri(new URIish(URL)); + remoteAddCommand.call(); + + setDefaultConfigSettings(git.getRepository()); + + // Set tracked master branch + setTrackedBranch(git.getRepository(), IGraficoConstants.MASTER); + + return git; + } + + @Override + public byte[] getFileContents(String path, String ref) throws IOException { + byte[] bytes = null; + + try (Repository repository = Git.open(getLocalRepositoryFolder()).getRepository()) { + ObjectId lastCommitId = repository.resolve(ref); + + try (RevWalk revWalk = new RevWalk(repository)) { + RevCommit commit = revWalk.parseCommit(lastCommitId); + RevTree tree = commit.getTree(); + + // now try to find a specific file + try (TreeWalk treeWalk = new TreeWalk(repository)) { + treeWalk.addTree(tree); + treeWalk.setRecursive(true); + treeWalk.setFilter(PathFilter.create(path)); + + // Not found, return null + if (!treeWalk.next()) { + return null; + } + + ObjectId objectId = treeWalk.getObjectId(0); + ObjectLoader loader = repository.open(objectId); + + bytes = loader.getBytes(); + } + + revWalk.dispose(); + } + } + + return bytes; + } + + @Override + public String getWorkingTreeFileContents(String path) throws IOException { + String str = ""; //$NON-NLS-1$ + + try (Git git = Git.open(getLocalRepositoryFolder())) { + try (BufferedReader in = new BufferedReader(new FileReader(new File(getLocalRepositoryFolder(), path)))) { + String line; + while ((line = in.readLine()) != null) { + str += line + "\n"; //$NON-NLS-1$ + } + } + } + + return str; + } + + @Override + public void resetToRef(String ref) throws IOException, GitAPIException { + // Check lock file is deleted + checkDeleteLockFile(); + + try (Git git = Git.open(getLocalRepositoryFolder())) { + // Reset to master + ResetCommand resetCommand = git.reset(); + resetCommand.setRef(ref); + resetCommand.setMode(ResetType.HARD); + resetCommand.call(); + + // Clean extra files + CleanCommand cleanCommand = git.clean(); + cleanCommand.setCleanDirectories(true); + cleanCommand.call(); + } + } + + @Override + public boolean isHeadAndRemoteSame() throws IOException, GitAPIException { + try (Repository repository = Git.open(getLocalRepositoryFolder()).getRepository()) { + // Get remote branch ref + BranchInfo currentRemoteBranch = getBranchStatus().getCurrentRemoteBranch(); + if (currentRemoteBranch == null) { + return false; + } + + // Remote + Ref remoteRef = currentRemoteBranch.getRef(); + + // Head + Ref headRef = repository.findRef(HEAD); + + // In case of missing ref return false + if (headRef == null || remoteRef == null) { + return false; + } + + return headRef.getObjectId().equals(remoteRef.getObjectId()); + } + } + + @Override + public void exportModelToGraficoFiles() throws IOException, GitAPIException { + // Open the model before showing the progress monitor + IArchimateModel model = IEditorModelManager.INSTANCE.openModel(getTempModelFile()); + + if (model == null) { + throw new IOException(Messages.ArchiRepository_0); + } + + final Exception[] exception = new Exception[1]; + + try { + // When using this be careful that no UI operations are called as this could + // lead to an SWT Invalid thread access exception + // This will show a Cancel button which will not cancel, but this progress + // monitor is the only one which does not freeze the UI + PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor pm) { + pm.beginTask(Messages.ArchiRepository_1, IProgressMonitor.UNKNOWN); + + try { + // Export + GraficoModelExporter exporter = new GraficoModelExporter(model, getLocalRepositoryFolder()); + exporter.exportModel(); + + // Check lock file is deleted + checkDeleteLockFile(); + + // Stage modified files to index - this can take a long time! + // This will clear any different line endings and calls to git.status() will be + // faster + try (Git git = Git.open(getLocalRepositoryFolder())) { + AddCommand addCommand = git.add(); + addCommand.addFilepattern("."); //$NON-NLS-1$ + addCommand.setUpdate(false); + addCommand.call(); + } + } catch (IOException | GitAPIException ex) { + exception[0] = ex; + } + } + }); + } catch (InvocationTargetException | InterruptedException ex) { + throw new IOException(ex); + } + + if (exception[0] instanceof IOException) { + throw (IOException) exception[0]; + } + if (exception[0] instanceof GitAPIException) { + throw (GitAPIException) exception[0]; + } + } + + @Override + public PersonIdent getUserDetails() throws IOException { + try (Git git = Git.open(getLocalRepositoryFolder())) { + StoredConfig config = git.getRepository().getConfig(); + String name = StringUtils.safeString( + config.getString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_NAME)); + String email = StringUtils.safeString( + config.getString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_EMAIL)); + return new PersonIdent(name, email); + } + } + + @Override + public void saveUserDetails(String name, String email) throws IOException { + // Get global user details from .gitconfig for comparison + PersonIdent global = new PersonIdent("", ""); //$NON-NLS-1$ //$NON-NLS-2$ + + try { + global = GraficoUtils.getGitConfigUserDetails(); + } catch (ConfigInvalidException ex) { + ex.printStackTrace(); + } + + // Save to local config + try (Git git = Git.open(getLocalRepositoryFolder())) { + StoredConfig config = git.getRepository().getConfig(); + + // If global name == local name or blank then unset + if (!StringUtils.isSet(name) || global.getName().equals(name)) { + config.unset(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_NAME); + } + // Set + else { + config.setString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_NAME, name); + } + + // If global email == local email or blank then unset + if (!StringUtils.isSet(email) || global.getEmailAddress().equals(email)) { + config.unset(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_EMAIL); + } else { + config.setString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_EMAIL, email); + } + + config.save(); + } + } + + @Override + public boolean equals(Object obj) { + if ((obj != null) && (obj instanceof ArchiRepository)) { + return fLocalRepoFolder != null + && fLocalRepoFolder.equals(((IArchiRepository) obj).getLocalRepositoryFolder()); + } + return false; + } + + /** + * Set default settings in the config file + * + * @param repository + * @throws IOException + */ + private void setDefaultConfigSettings(Repository repository) throws IOException { + StoredConfig config = repository.getConfig(); + + /* + * Set Line endings in the config file to autocrlf=input This ensures that files + * are not seen as different + */ + config.setString(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_AUTOCRLF, "input"); //$NON-NLS-1$ + + /* + * Set longpaths=true because garbage collection is not possible otherwise See + * https://stackoverflow.com/questions/22575662/filename-too-long-in-git-for- + * windows + */ + config.setString(ConfigConstants.CONFIG_CORE_SECTION, null, "longpaths", "true"); //$NON-NLS-1$ //$NON-NLS-2$ + + config.save(); + } + + /** + * Set the given branchName to track "origin" + */ + private void setTrackedBranch(Repository repository, String branchName) throws IOException { + if (branchName == null) { + return; + } + + StoredConfig config = repository.getConfig(); + + if (!IGraficoConstants.ORIGIN.equals(config.getString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, + ConfigConstants.CONFIG_KEY_REMOTE))) { + config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_REMOTE, + IGraficoConstants.ORIGIN); + config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_MERGE, + Constants.R_HEADS + branchName); + config.save(); + } + } + + @Override + public boolean hasLocalChanges() throws IOException { + String latestChecksum = getLatestChecksum(); + if (latestChecksum == null) { + return false; + } + + String currentChecksum = createChecksum(); + return !latestChecksum.equals(currentChecksum); + } + + @Override + public boolean saveChecksum() throws IOException { + // Get the file's checksum as string + String checksum = createChecksum(); + if (checksum == null) { + return false; + } + + File checksumFile = new File(getLocalGitFolder(), "checksum"); //$NON-NLS-1$ + Files.write(Paths.get(checksumFile.getAbsolutePath()), checksum.getBytes(), StandardOpenOption.CREATE); + + return true; + } + + @Override + public BranchStatus getBranchStatus() throws IOException, GitAPIException { + return new BranchStatus(this); + } + + private String getLatestChecksum() throws IOException { + File checksumFile = new File(getLocalGitFolder(), "checksum"); //$NON-NLS-1$ + if (!checksumFile.exists()) { + return null; + } + + byte[] bytes = Files.readAllBytes(Paths.get(checksumFile.getAbsolutePath())); + return new String(bytes); + } + + private String createChecksum() throws IOException { + File tempFile = getTempModelFile(); + + if (tempFile == null) { + return null; + } + + MessageDigest digest = null; + try { + digest = MessageDigest.getInstance("MD5"); //$NON-NLS-1$ + } catch (NoSuchAlgorithmException ex) { + throw new IOException("NoSuchAlgorithm Exception", ex); //$NON-NLS-1$ + } + + // Get file input stream for reading the file content + FileInputStream fis = new FileInputStream(tempFile); + + // Create byte array to read data in chunks + byte[] byteArray = new byte[1024]; + int bytesCount = 0; + + // Read file data and update in message digest + while ((bytesCount = fis.read(byteArray)) != -1) { + digest.update(byteArray, 0, bytesCount); + } + + fis.close(); + + // Get the hash's bytes + byte[] bytes = digest.digest(); + + // This bytes[] has bytes in decimal format; + // Convert it to hexadecimal format + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < bytes.length; i++) { + sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1)); + } + + return sb.toString(); + } + + /** + * In some cases the lock file exists and leads to an error, so we delete it + */ + private void checkDeleteLockFile() { + File lockFile = new File(getLocalGitFolder(), "index.lock"); //$NON-NLS-1$ + if (lockFile.exists() && lockFile.canWrite()) { + lockFile.delete(); + } + } } diff --git a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/preferences/ModelRepositoryPreferencePage.java b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/preferences/ModelRepositoryPreferencePage.java index 601a881a..cd819b26 100644 --- a/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/preferences/ModelRepositoryPreferencePage.java +++ b/org.archicontribs.modelrepository/src/org/archicontribs/modelrepository/preferences/ModelRepositoryPreferencePage.java @@ -228,6 +228,8 @@ public void widgetSelected(SelectionEvent e) { gd = new GridData(GridData.FILL_HORIZONTAL); fStoreCredentialsButton.setLayoutData(gd); + //HTTP Skip SSL verification + // Proxy Group