001/* 002 * JDrupes GitVersioning 003 * Copyright (C) 2025 Michael N. Lipp 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <https://www.gnu.org/licenses/>. 017 */ 018 019package org.jdrupes.gitversioning.api; 020 021import java.nio.file.Path; 022import java.util.List; 023import java.util.Objects; 024import java.util.ServiceLoader; 025import java.util.ServiceLoader.Provider; 026import java.util.stream.Stream; 027import org.eclipse.jgit.api.Git; 028import org.eclipse.jgit.api.Status; 029import org.eclipse.jgit.api.errors.GitAPIException; 030import org.eclipse.jgit.lib.Repository; 031 032/** 033 * Defines a configurable version evaluator. 034 */ 035public interface VersionEvaluator { 036 037 /** 038 * Creates a version evaluator for the given repository. The 039 * implementation is looked up using the [ServiceLoader] mechanism 040 * with the given class loader. 041 * 042 * @param repository the repository 043 * @param classLoader the class loader 044 * @return the version evaluator 045 */ 046 static VersionEvaluator forRepository(Repository repository, 047 ClassLoader classLoader) { 048 ServiceLoader<VersionEvaluatorProvider> loader 049 = ServiceLoader.load(VersionEvaluatorProvider.class, classLoader); 050 return loader.findFirst().orElseThrow().repository(repository); 051 } 052 053 /** 054 * Creates a version evaluator for the given repository. The 055 * implementation is looked up using the [ServiceLoader] mechanism, 056 * using the class loaders of the current thread and the 057 * [VersionEvaluator] class. 058 * 059 * @param repository the repository 060 * @return the version evaluator 061 */ 062 static VersionEvaluator forRepository(Repository repository) { 063 return Stream.of(Thread.currentThread().getContextClassLoader(), 064 VersionEvaluator.class.getClassLoader()).filter(Objects::nonNull) 065 .map(cl -> ServiceLoader.load(VersionEvaluatorProvider.class, cl) 066 .stream()) 067 .flatMap(s -> s).findFirst().map(Provider::get).orElseThrow() 068 .repository(repository); 069 } 070 071 /** 072 * Searches the sub directory for changes (any of combines added, 073 * changed, removed, missing, modified, conflicting or untracked). 074 * 075 * @param repository the repository 076 * @param subDir the sub dir 077 * @return true, if is dirty 078 * @throws GitAPIException the git API exception 079 */ 080 static List<Path> dirtyFiles(Repository repository, Path subDir) 081 throws GitAPIException { 082 try (Git git = Git.wrap(repository)) { 083 Status status = git.status().call(); 084 var useAll = subDir == null || Path.of("").equals(subDir); 085 086 // Uncommitted combines added, changed, removed, missing, 087 // modified and conflicting 088 return Stream.concat(status.getUncommittedChanges().stream(), 089 status.getUntracked().stream()).map(Path::of) 090 .filter(path -> useAll || path.startsWith(subDir)) 091 .toList(); 092 } 093 } 094 095 /** 096 * Sets the sub directory of the work tree that is relevant for 097 * evaluating the version. Usually, only files in this directory are 098 * checked for changes, resulting in a "dirty" in the version. 099 * 100 * @param subDirectory the sub directory 101 * @return the version evaluator 102 */ 103 VersionEvaluator subDirectory(Path subDirectory); 104 105 /** 106 * Sets the tag filter to use. 107 * 108 * @param tagFilter the tag filter 109 * @return the version evaluator 110 */ 111 VersionEvaluator tagFilter(TagFilter tagFilter); 112 113 /** 114 * Sets the tag processor to use. 115 * 116 * @param tagProcessor the tag processor 117 * @return the version evaluator 118 */ 119 VersionEvaluator tagProcessor(TagProcessor tagProcessor); 120 121 /** 122 * Returns the evaluated version. 123 * 124 * @return the string 125 */ 126 String version(); 127}