/* * Copyright 2013 gitblit.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gitblit; import java.text.MessageFormat; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.RefUpdate.Result; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.TrackingRefUpdate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.utils.JGitUtils; /** * The Mirror executor handles periodic fetching of mirrored repositories. * * @author James Moger * */ public class MirrorExecutor implements Runnable { private final Logger logger = LoggerFactory.getLogger(MirrorExecutor.class); private final Set repairAttempted = Collections.synchronizedSet(new HashSet()); private final IStoredSettings settings; private AtomicBoolean running = new AtomicBoolean(false); private AtomicBoolean forceClose = new AtomicBoolean(false); private final UserModel gitblitUser; public MirrorExecutor(IStoredSettings settings) { this.settings = settings; this.gitblitUser = new UserModel("gitblit"); this.gitblitUser.displayName = "Gitblit"; } public boolean isReady() { return settings.getBoolean(Keys.git.enableMirroring, false); } public boolean isRunning() { return running.get(); } public void close() { forceClose.set(true); } @Override public void run() { if (!isReady()) { return; } running.set(true); for (String repositoryName : GitBlit.self().getRepositoryList()) { if (forceClose.get()) { break; } if (GitBlit.self().isCollectingGarbage(repositoryName)) { logger.debug("mirror is skipping {} garbagecollection", repositoryName); continue; } RepositoryModel model = null; Repository repository = null; try { model = GitBlit.self().getRepositoryModel(repositoryName); if (!model.isMirror && !model.isBare) { // repository must be a valid bare git mirror logger.debug("mirror is skipping {} !mirror !bare", repositoryName); continue; } repository = GitBlit.self().getRepository(repositoryName); if (repository == null) { logger.warn(MessageFormat.format("MirrorExecutor is missing repository {0}?!?", repositoryName)); continue; } // automatically repair (some) invalid fetch ref specs if (!repairAttempted.contains(repositoryName)) { repairAttempted.add(repositoryName); JGitUtils.repairFetchSpecs(repository); } // find the first mirror remote - there should only be one StoredConfig rc = repository.getConfig(); RemoteConfig mirror = null; List configs = RemoteConfig.getAllRemoteConfigs(rc); for (RemoteConfig config : configs) { if (config.isMirror()) { mirror = config; break; } } if (mirror == null) { // repository does not have a mirror remote logger.debug("mirror is skipping {} no mirror remote found", repositoryName); continue; } logger.debug("checking {} remote {} for ref updates", repositoryName, mirror.getName()); final boolean testing = false; Git git = new Git(repository); FetchResult result = git.fetch().setRemote(mirror.getName()).setDryRun(testing).call(); Collection refUpdates = result.getTrackingRefUpdates(); if (refUpdates.size() > 0) { for (TrackingRefUpdate ru : refUpdates) { StringBuilder sb = new StringBuilder(); sb.append("updated mirror "); sb.append(repositoryName); sb.append(" "); sb.append(ru.getRemoteName()); sb.append(" -> "); sb.append(ru.getLocalName()); if (ru.getResult() == Result.FORCED) { sb.append(" (forced)"); } sb.append(" "); sb.append(ru.getOldObjectId() == null ? "" : ru.getOldObjectId().abbreviate(7).name()); sb.append(".."); sb.append(ru.getNewObjectId() == null ? "" : ru.getNewObjectId().abbreviate(7).name()); logger.info(sb.toString()); } } } catch (Exception e) { logger.error("Error updating mirror " + repositoryName, e); } finally { // cleanup if (repository != null) { repository.close(); } } } running.set(false); } }