| | |
| | | import java.util.Collections; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.TreeMap; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.Executors; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | |
| | | |
| | | import org.apache.wicket.resource.ContextRelativeResource; |
| | | import org.apache.wicket.util.resource.ResourceStreamNotFoundException; |
| | | import org.eclipse.jgit.storage.file.FileBasedConfig; |
| | | import org.eclipse.jgit.util.FS; |
| | | import org.slf4j.Logger; |
| | | |
| | | import com.gitblit.Constants.AccessPermission; |
| | |
| | | import com.gitblit.models.FederationProposal; |
| | | import com.gitblit.models.FederationSet; |
| | | import com.gitblit.models.GitClientApplication; |
| | | import com.gitblit.models.ProjectModel; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.RepositoryUrl; |
| | | import com.gitblit.models.ServerSettings; |
| | |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.ArrayUtils; |
| | | import com.gitblit.utils.ContainerUtils; |
| | | import com.gitblit.utils.DeepCopier; |
| | | import com.gitblit.utils.FederationUtils; |
| | | import com.gitblit.utils.HttpUtils; |
| | | import com.gitblit.utils.JGitUtils; |
| | | import com.gitblit.utils.JsonUtils; |
| | | import com.gitblit.utils.ModelUtils; |
| | | import com.gitblit.utils.ObjectCache; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.gitblit.wicket.GitblitWicketFilter; |
| | |
| | | */ |
| | | @WebListener |
| | | public class GitBlit extends DaggerContextListener |
| | | implements IProjectManager, |
| | | IFederationManager, |
| | | implements IFederationManager, |
| | | IGitblitManager { |
| | | |
| | | private static GitBlit gitblit; |
| | |
| | | |
| | | private final Map<String, FederationModel> federationPullResults = new ConcurrentHashMap<String, FederationModel>(); |
| | | |
| | | private final Map<String, ProjectModel> projectCache = new ConcurrentHashMap<String, ProjectModel>(); |
| | | |
| | | private final ObjectCache<String> projectMarkdownCache = new ObjectCache<String>(); |
| | | |
| | | private final ObjectCache<String> projectRepositoriesMarkdownCache = new ObjectCache<String>(); |
| | | |
| | | private IStoredSettings settings; |
| | | |
| | | private FileBasedConfig projectConfigs; |
| | | |
| | | private FanoutService fanoutService; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | private void reloadProjectMarkdown(ProjectModel project) { |
| | | // project markdown |
| | | File pmkd = new File(getManager(IRepositoryManager.class).getRepositoriesFolder(), (project.isRoot ? "" : project.name) + "/project.mkd"); |
| | | if (pmkd.exists()) { |
| | | Date lm = new Date(pmkd.lastModified()); |
| | | if (!projectMarkdownCache.hasCurrent(project.name, lm)) { |
| | | String mkd = com.gitblit.utils.FileUtils.readContent(pmkd, "\n"); |
| | | projectMarkdownCache.updateObject(project.name, lm, mkd); |
| | | } |
| | | project.projectMarkdown = projectMarkdownCache.getObject(project.name); |
| | | } |
| | | |
| | | // project repositories markdown |
| | | File rmkd = new File(getManager(IRepositoryManager.class).getRepositoriesFolder(), (project.isRoot ? "" : project.name) + "/repositories.mkd"); |
| | | if (rmkd.exists()) { |
| | | Date lm = new Date(rmkd.lastModified()); |
| | | if (!projectRepositoriesMarkdownCache.hasCurrent(project.name, lm)) { |
| | | String mkd = com.gitblit.utils.FileUtils.readContent(rmkd, "\n"); |
| | | projectRepositoriesMarkdownCache.updateObject(project.name, lm, mkd); |
| | | } |
| | | project.repositoriesMarkdown = projectRepositoriesMarkdownCache.getObject(project.name); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the map of project config. This map is cached and reloaded if |
| | | * the underlying projects.conf file changes. |
| | | * |
| | | * @return project config map |
| | | */ |
| | | private Map<String, ProjectModel> getProjectConfigs() { |
| | | if (projectCache.isEmpty() || projectConfigs.isOutdated()) { |
| | | |
| | | try { |
| | | projectConfigs.load(); |
| | | } catch (Exception e) { |
| | | } |
| | | |
| | | // project configs |
| | | String rootName = settings.getString(Keys.web.repositoryRootGroupName, "main"); |
| | | ProjectModel rootProject = new ProjectModel(rootName, true); |
| | | |
| | | Map<String, ProjectModel> configs = new HashMap<String, ProjectModel>(); |
| | | // cache the root project under its alias and an empty path |
| | | configs.put("", rootProject); |
| | | configs.put(rootProject.name.toLowerCase(), rootProject); |
| | | |
| | | for (String name : projectConfigs.getSubsections("project")) { |
| | | ProjectModel project; |
| | | if (name.equalsIgnoreCase(rootName)) { |
| | | project = rootProject; |
| | | } else { |
| | | project = new ProjectModel(name); |
| | | } |
| | | project.title = projectConfigs.getString("project", name, "title"); |
| | | project.description = projectConfigs.getString("project", name, "description"); |
| | | |
| | | reloadProjectMarkdown(project); |
| | | |
| | | configs.put(name.toLowerCase(), project); |
| | | } |
| | | projectCache.clear(); |
| | | projectCache.putAll(configs); |
| | | } |
| | | return projectCache; |
| | | } |
| | | |
| | | /** |
| | | * Returns a list of project models for the user. |
| | | * |
| | | * @param user |
| | | * @param includeUsers |
| | | * @return list of projects that are accessible to the user |
| | | */ |
| | | @Override |
| | | public List<ProjectModel> getProjectModels(UserModel user, boolean includeUsers) { |
| | | Map<String, ProjectModel> configs = getProjectConfigs(); |
| | | |
| | | // per-user project lists, this accounts for security and visibility |
| | | Map<String, ProjectModel> map = new TreeMap<String, ProjectModel>(); |
| | | // root project |
| | | map.put("", configs.get("")); |
| | | |
| | | for (RepositoryModel model : getManager(IRepositoryManager.class).getRepositoryModels(user)) { |
| | | String rootPath = StringUtils.getRootPath(model.name).toLowerCase(); |
| | | if (!map.containsKey(rootPath)) { |
| | | ProjectModel project; |
| | | if (configs.containsKey(rootPath)) { |
| | | // clone the project model because it's repository list will |
| | | // be tailored for the requesting user |
| | | project = DeepCopier.copy(configs.get(rootPath)); |
| | | } else { |
| | | project = new ProjectModel(rootPath); |
| | | } |
| | | map.put(rootPath, project); |
| | | } |
| | | map.get(rootPath).addRepository(model); |
| | | } |
| | | |
| | | // sort projects, root project first |
| | | List<ProjectModel> projects; |
| | | if (includeUsers) { |
| | | // all projects |
| | | projects = new ArrayList<ProjectModel>(map.values()); |
| | | Collections.sort(projects); |
| | | projects.remove(map.get("")); |
| | | projects.add(0, map.get("")); |
| | | } else { |
| | | // all non-user projects |
| | | projects = new ArrayList<ProjectModel>(); |
| | | ProjectModel root = map.remove(""); |
| | | for (ProjectModel model : map.values()) { |
| | | if (!model.isUserProject()) { |
| | | projects.add(model); |
| | | } |
| | | } |
| | | Collections.sort(projects); |
| | | projects.add(0, root); |
| | | } |
| | | return projects; |
| | | } |
| | | |
| | | /** |
| | | * Returns the project model for the specified user. |
| | | * |
| | | * @param name |
| | | * @param user |
| | | * @return a project model, or null if it does not exist |
| | | */ |
| | | @Override |
| | | public ProjectModel getProjectModel(String name, UserModel user) { |
| | | for (ProjectModel project : getProjectModels(user, true)) { |
| | | if (project.name.equalsIgnoreCase(name)) { |
| | | return project; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Returns a project model for the Gitblit/system user. |
| | | * |
| | | * @param name a project name |
| | | * @return a project model or null if the project does not exist |
| | | */ |
| | | @Override |
| | | public ProjectModel getProjectModel(String name) { |
| | | Map<String, ProjectModel> configs = getProjectConfigs(); |
| | | ProjectModel project = configs.get(name.toLowerCase()); |
| | | if (project == null) { |
| | | project = new ProjectModel(name); |
| | | if (ModelUtils.isPersonalRepository(name)) { |
| | | UserModel user = getManager(IUserManager.class).getUserModel(ModelUtils.getUserNameFromRepoPath(name)); |
| | | if (user != null) { |
| | | project.title = user.getDisplayName(); |
| | | project.description = "personal repositories"; |
| | | } |
| | | } |
| | | } else { |
| | | // clone the object |
| | | project = DeepCopier.copy(project); |
| | | } |
| | | if (StringUtils.isEmpty(name)) { |
| | | // get root repositories |
| | | for (String repository : getManager(IRepositoryManager.class).getRepositoryList()) { |
| | | if (repository.indexOf('/') == -1) { |
| | | project.addRepository(repository); |
| | | } |
| | | } |
| | | } else { |
| | | // get repositories in subfolder |
| | | String folder = name.toLowerCase() + "/"; |
| | | for (String repository : getManager(IRepositoryManager.class).getRepositoryList()) { |
| | | if (repository.toLowerCase().startsWith(folder)) { |
| | | project.addRepository(repository); |
| | | } |
| | | } |
| | | } |
| | | if (project.repositories.size() == 0) { |
| | | // no repositories == no project |
| | | return null; |
| | | } |
| | | |
| | | reloadProjectMarkdown(project); |
| | | return project; |
| | | } |
| | | |
| | | /** |
| | | * Returns the list of project models that are referenced by the supplied |
| | | * repository model list. This is an alternative method exists to ensure |
| | | * Gitblit does not call getRepositoryModels(UserModel) twice in a request. |
| | | * |
| | | * @param repositoryModels |
| | | * @param includeUsers |
| | | * @return a list of project models |
| | | */ |
| | | @Override |
| | | public List<ProjectModel> getProjectModels(List<RepositoryModel> repositoryModels, boolean includeUsers) { |
| | | Map<String, ProjectModel> projects = new LinkedHashMap<String, ProjectModel>(); |
| | | for (RepositoryModel repository : repositoryModels) { |
| | | if (!includeUsers && repository.isPersonalRepository()) { |
| | | // exclude personal repositories |
| | | continue; |
| | | } |
| | | if (!projects.containsKey(repository.projectPath)) { |
| | | ProjectModel project = getProjectModel(repository.projectPath); |
| | | if (project == null) { |
| | | logger.warn(MessageFormat.format("excluding project \"{0}\" from project list because it is empty!", |
| | | repository.projectPath)); |
| | | continue; |
| | | } |
| | | projects.put(repository.projectPath, project); |
| | | // clear the repo list in the project because that is the system |
| | | // list, not the user-accessible list and start building the |
| | | // user-accessible list |
| | | project.repositories.clear(); |
| | | project.repositories.add(repository.name); |
| | | project.lastChange = repository.lastChange; |
| | | } else { |
| | | // update the user-accessible list |
| | | // this is used for repository count |
| | | ProjectModel project = projects.get(repository.projectPath); |
| | | project.repositories.add(repository.name); |
| | | if (project.lastChange.before(repository.lastChange)) { |
| | | project.lastChange = repository.lastChange; |
| | | } |
| | | } |
| | | } |
| | | return new ArrayList<ProjectModel>(projects.values()); |
| | | } |
| | | |
| | | /** |
| | | * Returns Gitblit's scheduled executor service for scheduling tasks. |
| | |
| | | getManager(IUserManager.class), |
| | | getManager(ISessionManager.class), |
| | | getManager(IRepositoryManager.class), |
| | | this, |
| | | getManager(IProjectManager.class), |
| | | this, |
| | | this); |
| | | gitDaemon = new GitDaemon(gitblit); |
| | |
| | | startManager(injector, IUserManager.class); |
| | | startManager(injector, ISessionManager.class); |
| | | startManager(injector, IRepositoryManager.class); |
| | | startManager(injector, IProjectManager.class); |
| | | |
| | | logger.info("Gitblit base folder = " + baseFolder.getAbsolutePath()); |
| | | |
| | | loadSettingModels(runtime.getSettingsModel()); |
| | | |
| | | // load and cache the project metadata |
| | | projectConfigs = new FileBasedConfig(runtime.getFileOrFolder(Keys.web.projectsFile, "${baseFolder}/projects.conf"), FS.detect()); |
| | | getProjectConfigs(); |
| | | |
| | | if (true/*startFederation*/) { |
| | | configureFederation(); |