001package co.codewizards.cloudstore.client; 002 003import java.io.File; 004import java.net.MalformedURLException; 005import java.net.URL; 006import java.util.ArrayList; 007import java.util.Collection; 008import java.util.HashMap; 009import java.util.List; 010import java.util.Map; 011import java.util.UUID; 012 013import org.kohsuke.args4j.Argument; 014import org.kohsuke.args4j.Option; 015import org.slf4j.Logger; 016import org.slf4j.LoggerFactory; 017 018import co.codewizards.cloudstore.core.progress.LoggerProgressMonitor; 019import co.codewizards.cloudstore.core.repo.local.LocalRepoManager; 020import co.codewizards.cloudstore.core.repo.local.LocalRepoManagerFactory; 021import co.codewizards.cloudstore.core.repo.local.LocalRepoRegistry; 022import co.codewizards.cloudstore.core.repo.local.LocalRepoTransaction; 023import co.codewizards.cloudstore.core.repo.sync.RepoToRepoSync; 024import co.codewizards.cloudstore.local.persistence.RemoteRepository; 025import co.codewizards.cloudstore.local.persistence.RemoteRepositoryDAO; 026 027public class SyncSubCommand extends SubCommandWithExistingLocalRepo { 028 private static final Logger logger = LoggerFactory.getLogger(SyncSubCommand.class); 029 030 @Argument(metaVar="<remote>", index=1, required=false, usage="An ID or URL of a remote repository. If none is specified, all remote repositories are synced.") 031 private String remote; 032 033 private UUID remoteRepositoryId; 034 private URL remoteRoot; 035 036 @Option(name="-localOnly", required=false, usage="Synchronise locally only. Do not communicate with any remote repository.") 037 private boolean localOnly; 038 039 @Override 040 public String getSubCommandDescription() { 041 return "Synchronise a local repository. Depending on the parameters, it synchronises only locally or with one or more remote repositories."; 042 } 043 044 @Override 045 public void prepare() throws Exception { 046 super.prepare(); 047 remoteRepositoryId = null; 048 remoteRoot = null; 049 if (remote != null && !remote.isEmpty()) { 050 try { 051 remoteRepositoryId = UUID.fromString(remote); 052 } catch (IllegalArgumentException x) { 053 try { 054 remoteRoot = new URL(remote); 055 } catch (MalformedURLException y) { 056 throw new IllegalArgumentException(String.format("<remote> '%s' is neither a valid repositoryId nor a valid URL!", remote)); 057 } 058 } 059 } 060 } 061 062 @Override 063 protected void assertLocalRootNotNull() { 064 if (!isAll()) 065 super.assertLocalRootNotNull(); 066 } 067 068 @Override 069 public void run() throws Exception { 070 if (isAll()) { 071 for (UUID repositoryId : LocalRepoRegistry.getInstance().getRepositoryIds()) 072 sync(repositoryId); 073 } 074 else 075 sync(localRoot); 076 } 077 078 private void sync(UUID repositoryId) { 079 File localRoot = LocalRepoRegistry.getInstance().getLocalRootOrFail(repositoryId); 080 sync(localRoot); 081 } 082 083 private void sync(File localRoot) { 084 List<URL> remoteRoots = new ArrayList<URL>(); 085 Map<UUID, URL> filteredRemoteRepositoryId2RemoteRoot = new HashMap<UUID, URL>(); 086 UUID repositoryId; 087 LocalRepoManager localRepoManager = LocalRepoManagerFactory.Helper.getInstance().createLocalRepoManagerForExistingRepository(localRoot); 088 try { 089 if (localOnly) { 090 localRepoManager.localSync(new LoggerProgressMonitor(logger)); 091 return; 092 } 093 094 repositoryId = localRepoManager.getRepositoryId(); 095 localRoot = localRepoManager.getLocalRoot(); 096 LocalRepoTransaction transaction = localRepoManager.beginReadTransaction(); 097 try { 098 Collection<RemoteRepository> remoteRepositories = transaction.getDAO(RemoteRepositoryDAO.class).getObjects(); 099 for (RemoteRepository remoteRepository : remoteRepositories) { 100 if (remoteRepository.getRemoteRoot() == null) 101 continue; 102 103 remoteRoots.add(remoteRepository.getRemoteRoot()); 104 if ((remoteRepositoryId == null && remoteRoot == null) 105 || (remoteRepositoryId != null && remoteRepositoryId.equals(remoteRepository.getRepositoryId())) 106 || (remoteRoot != null && remoteRoot.equals(remoteRepository.getRemoteRoot()))) 107 filteredRemoteRepositoryId2RemoteRoot.put(remoteRepository.getRepositoryId(), remoteRepository.getRemoteRoot()); 108 } 109 110 transaction.commit(); 111 } finally { 112 transaction.rollbackIfActive(); 113 } 114 } finally { 115 localRepoManager.close(); 116 } 117 118 if (remoteRoots.isEmpty()) 119 System.err.println(String.format("WARNING: The repository %s ('%s') is not connected to any remote repository as client!", repositoryId, localRoot)); 120 else if (filteredRemoteRepositoryId2RemoteRoot.isEmpty()) 121 System.err.println(String.format("WARNING: The repository %s ('%s') is not connected to the specified remote repository ('%s')!", repositoryId, localRoot, remote)); 122 else { 123 for (Map.Entry<UUID, URL> me : filteredRemoteRepositoryId2RemoteRoot.entrySet()) { 124 UUID remoteRepositoryId = me.getKey(); 125 URL remoteRoot = me.getValue(); 126 System.out.println("********************************************************************************"); 127 System.out.println(String.format("Syncing %s ('%s') with %s ('%s').", repositoryId, localRoot, remoteRepositoryId, remoteRoot)); 128 System.out.println("********************************************************************************"); 129 RepoToRepoSync repoToRepoSync = new RepoToRepoSync(localRoot, remoteRoot); 130 try { 131 repoToRepoSync.sync(new LoggerProgressMonitor(logger)); 132 } finally { 133 repoToRepoSync.close(); 134 } 135 } 136 } 137 } 138 139 private boolean isAll() { 140 return "ALL".equals(local); 141 } 142}