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