package com.perforce.hws.gf; import ca.szc.configparser.Ini; import com.perforce.hws.p4base.*; import com.perforce.hws.util.MapUtils; import com.perforce.hwsclient.models.*; import com.perforce.p4java.server.IServer; import java.io.*; import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; /** * Methods related to manipulating and parsing the Git Fusion configuration * directly. */ public interface GitFusionConfigMethods extends P4Methods, PathUtils, PrintMethods, TemporaryClient, MapUtils, GitFusionStringMethods { /** * Writes out the configuration map in .ini format. * * @param config * @return * @throws IOException */ default String writeGitFusionConfig(GitFusionRepoConfig config) throws IOException { Ini ini = new Ini(); Map<String, String> globalOptions = toRepoGlobalOverrideMap(config.getGlobalOverrides()); globalOptions.put("description", config.getDescription()); ini.getSections().put("@repo", globalOptions); config.getBranches() .forEach(c -> ini.getSections().put(c.getGitBranchId(), toRepoBranchMap(c))); StringWriter w = new StringWriter(); try (BufferedWriter bufferedWriter = new BufferedWriter(w)) { ini.write(bufferedWriter); } return w.getBuffer().toString(); } default Map<String, String> toRepoGlobalOverrideMap(GitFusionRepoGlobalOverrides globalOverrides) { Map<String, String> options = new HashMap<>(); if (globalOverrides == null) { return options; } putsIfSet(options, "charset", globalOverrides::getCharset); putsIfSet(options, "depot-path-repo-creation-enable", globalOverrides::getDepotPathRepoCreationEnable); putsIfSet(options, "depot-path-repo-creation-p4group", globalOverrides::getDepotPathRepoCreationP4group); putsIfSet(options, "change-owner", globalOverrides::getChangeOwner); putsIfSet(options, "enable-git-branch-creation", globalOverrides::getEnableGitBranchCreation); putsIfSet(options, "enable-swarm-reviews", globalOverrides::getEnableSwarmReviews); putsIfSet(options, "enable-git-merge-commits", globalOverrides::getEnableGitMergeCommits); putsIfSet(options, "enable-git-submodules", globalOverrides::getEnableGitSubmodules); putsIfSet(options, "ignore-author-permissions", globalOverrides::getIgnoreAuthorPermissions); putsIfSet(options, "preflight-commit", globalOverrides::getPreflightCommit); putsIfSet(options, "read-permission-check", globalOverrides::getReadPermissionCheck); putsIfSet(options, "git-merge-avoidance-after-change-num", globalOverrides::getGitMergeAvoidanceAfterChangeNum); putsIfSet(options, "job-lookup", globalOverrides::getJobLookup); putsIfSet(options, "depot-branch-creation-enable", globalOverrides::getDepotBranchCreationEnable); putsIfSet(options, "depot-branch-creation-p4group", globalOverrides::getDepotBranchCreationP4group); putsIfSet(options, "depot-branch-creation-depot-path", globalOverrides::getDepotBranchCreationDepotPath); putsIfSet(options, "depot-branch-creation-view", globalOverrides::getDepotBranchCreationView); putsIfSet(options, "enable-git-find-copies", globalOverrides::getEnableGitFindCopies); putsIfSet(options, "enable-git-find-renames", globalOverrides::getEnableGitFindRenames); putsIfSet(options, "enable-stream-imports", globalOverrides::getEnableStreamImports); putsIfSet(options, "http-url", globalOverrides::getHttpUrl); putsIfSet(options, "ssh-url", globalOverrides::getSshUrl); putsIfSet(options, "email-case-sensitivity", globalOverrides::getEmailCaseSensitivity); putsIfSet(options, "author-source", globalOverrides::getAuthorSource); putsIfSet(options, "limit_space_mb", globalOverrides::getLimitSpaceMb); putsIfSet(options, "limit_commits_received", globalOverrides::getLimitCommitsReceived); putsIfSet(options, "limit_files_received", globalOverrides::getLimitFilesReceived); putsIfSet(options, "limit_megabytes_received", globalOverrides::getLimitMegabytesReceived); return options; } default Map<String, String> toRepoBranchMap(GitFusionRepoBranchConfig config) { Map<String, String> options = new HashMap<>(); putsIfSet(options, "git-branch-name", config::getGitBranchName); putsIfSet(options, "view", () -> config.getView().stream().collect(Collectors.joining("\n"))); putsIfSet(options, "stream", config::getStream); putsIfSet(options, "read-only", config::getReadOnly); return options; } default GitFusionRepoConfig newRepoConfigFromIni(String iniSource) throws IOException { Ini ini = new Ini(); ini.read(new BufferedReader(new StringReader(iniSource))); Map<String, String> globalSection = ini.getSections().get("@repo"); GitFusionRepoConfig repoConfig = new GitFusionRepoConfig(); if (globalSection != null) { setsIfExists(repoConfig::setDescription, "description", globalSection); GitFusionRepoGlobalOverrides globalOverrides = toRepoGlobalOverridesFromMap(globalSection); repoConfig.setGlobalOverrides(globalOverrides); } List<GitFusionRepoBranchConfig> branchConfigs = ini.getSections().entrySet() .stream() .filter(entry -> !entry.getKey().equals("@repo")) .map(e -> { GitFusionRepoBranchConfig branchConfig = toRepoBranchConfigFromMap(e.getValue()); branchConfig.setGitBranchId(e.getKey()); return branchConfig; }) .collect(Collectors.toList()); repoConfig.setBranches(branchConfigs); return repoConfig; } default GitFusionRepoGlobalOverrides toRepoGlobalOverridesFromMap(Map<String, String> options) { GitFusionRepoGlobalOverrides overrides = new GitFusionRepoGlobalOverrides(); setsIfExists(overrides::setCharset, "charset", options); setsIfExists(overrides::setDepotPathRepoCreationEnable, "depot-path-repo-creation-enable", options); setsIfExists(overrides::setDepotPathRepoCreationP4group, "depot-path-repo-creation-p4group", options); setsIfExists(overrides::setChangeOwner, "change-owner", options); setsIfExists(overrides::setEnableGitBranchCreation, "enable-git-branch-creation", options); setsIfExists(overrides::setEnableSwarmReviews, "enable-swarm-reviews", options); setsIfExists(overrides::setEnableGitMergeCommits, "enable-git-merge-commits", options); setsIfExists(overrides::setEnableGitSubmodules, "enable-git-submodules", options); setsIfExists(overrides::setIgnoreAuthorPermissions, "ignore-author-permissions", options); setsIfExists(overrides::setPreflightCommit, "preflight-commit", options); setsIfExists(overrides::setReadPermissionCheck, "read-permission-check", options); setsIfExists(overrides::setGitMergeAvoidanceAfterChangeNum, "git-merge-avoidance-after-change-num", options); setsIfExists(overrides::setJobLookup, "job-lookup", options); setsIfExists(overrides::setDepotBranchCreationEnable, "depot-branch-creation-enable", options); setsIfExists(overrides::setDepotBranchCreationP4group, "depot-branch-creation-p4group", options); setsIfExists(overrides::setDepotBranchCreationDepotPath, "depot-branch-creation-depot-path", options); setsIfExists(overrides::setDepotBranchCreationView, "depot-branch-creation-view", options); setsIfExists(overrides::setEnableGitFindCopies, "enable-git-find-copies", options); setsIfExists(overrides::setEnableGitFindRenames, "enable-git-find-renames", options); setsIfExists(overrides::setEnableStreamImports, "enable-stream-imports", options); setsIfExists(overrides::setHttpUrl, "http-url", options); setsIfExists(overrides::setSshUrl, "ssh-url", options); setsIfExists(overrides::setEmailCaseSensitivity, "email-case-sensitivity", options); setsIfExists(overrides::setAuthorSource, "author-source", options); setsIfExists(overrides::setLimitSpaceMb, "limit_space_mb", options); setsIfExists(overrides::setLimitCommitsReceived, "limit_commits_received", options); setsIfExists(overrides::setLimitFilesReceived, "limit_files_received", options); setsIfExists(overrides::setLimitMegabytesReceived, "limit_megabytes_received", options); return overrides; } default GitFusionRepoBranchConfig toRepoBranchConfigFromMap(Map<String, String> options) { GitFusionRepoBranchConfig config = new GitFusionRepoBranchConfig(); setsIfExists(config::setGitBranchName, "git-branch-name", options); setsIfExists(s -> config.setView(Arrays.asList(s.split("\n"))), "view", options); setsIfExists(config::setStream, "stream", options); setsIfExists(config::setReadOnly, "read-only", options); return config; } /** * Loads the list of git fusion repositories. * * @param serverSupplier The P4 connection supplier * @param gitFusionDepot The Git Fusion depot name in the P4 server * @return A map containing 'id' and 'name' attributes. * @throws IOException */ default List<GitFusionRepoId> listGitFusionRepos(Supplier<IServer> serverSupplier, String gitFusionDepot) throws IOException { String pattern = String.format("//%s/repos/*/p4gf_config", gitFusionDepot); List<ResultMap> results = exec(serverSupplier, "files", "-e", pattern); final Pattern re = Pattern.compile( String.format("^//%s/repos/(?<repo>.*)/p4gf_config$", gitFusionDepot)); return results.stream() .filter(r -> r.containsKey("depotFile")) .map(r -> { GitFusionRepoId id = null; Matcher matcher = re.matcher((String)r.get("depotFile")); if (matcher.matches()) { id = new GitFusionRepoId(); String path = matcher.group("repo"); id.setName(decodeGF(path)); id.setId(path); } return id; }) .filter(id -> id != null) .collect(Collectors.toList()); } /** * Loads the single Git Fusion repository configuration. * * @param serverSupplier * @param gitFusionDepot * @param repoId * @return */ default GitFusionRepoConfig loadGitFusionRepoConfig( Supplier<IServer> serverSupplier, String gitFusionDepot, String repoId) throws IOException { String depotPath = String.format("//%s/repos/%s/p4gf_config", gitFusionDepot, repoId); if (hasSpecialChars(depotPath)) { throw new IllegalArgumentException("No wildcards allowed in repo " + "config locations"); } byte content[] = printFile(serverSupplier, depotPath); GitFusionRepoConfig config = newRepoConfigFromIni(new String(content, "UTF-8")); config.setName(decodeGF(repoId)); return config; } default List<ResultMap> replaceGitFusionRepoConfig( Supplier<IServer> serverSupplier, String gitFusionDepot, String repoId, GitFusionRepoConfig config, String changeDescription) throws IOException { String depotPath = String.format("//%s/repos/%s/p4gf_config", gitFusionDepot, repoId); if (hasSpecialChars(depotPath)) { throw new IllegalArgumentException("No wildcards allowed in repo " + "config locations"); } ChangelistRequest changelistRequest = new ChangelistRequest(); List<ChangelistAction> actions = new ArrayList<>(); ChangelistAction action = new ChangelistAction(); action.setActionType("upload"); action.setDepotFile(depotPath); String content = Base64.getEncoder().encodeToString(writeGitFusionConfig(config).getBytes()); action.setContent(content); actions.add(action); changelistRequest.setActions(actions); changelistRequest.setDescription(changeDescription); CreateChange createChange = new CreateChange(serverSupplier); return createChange.apply(changelistRequest); } default List<ResultMap> patchGitFusionRepoConfig( Supplier<IServer> serverSupplier, String gitFusionDepot, String repoId, GitFusionRepoConfig updates, String changeDescription) throws IOException { GitFusionRepoConfig current = loadGitFusionRepoConfig(serverSupplier, gitFusionDepot, repoId); copyIfSet(updates::getDescription, current::setDescription); if (updates.getGlobalOverrides() != null) { copyGlobalOverrides(updates.getGlobalOverrides(), current.getGlobalOverrides()); } updates.getBranches().forEach(u -> updateBranchConfig(current, u)); return replaceGitFusionRepoConfig(serverSupplier, gitFusionDepot, repoId, current, changeDescription); } default void copyGlobalOverrides(GitFusionRepoGlobalOverrides src, GitFusionRepoGlobalOverrides target) { copyIfSet(src::getCharset, target::setCharset); copyIfSet(src::getDepotPathRepoCreationEnable, target::setDepotPathRepoCreationEnable); copyIfSet(src::getDepotPathRepoCreationP4group, target::setDepotPathRepoCreationP4group); copyIfSet(src::getChangeOwner, target::setChangeOwner); copyIfSet(src::getEnableGitBranchCreation, target::setEnableGitBranchCreation); copyIfSet(src::getEnableSwarmReviews, target::setEnableSwarmReviews); copyIfSet(src::getEnableGitMergeCommits, target::setEnableGitMergeCommits); copyIfSet(src::getEnableGitSubmodules, target::setEnableGitSubmodules); copyIfSet(src::getIgnoreAuthorPermissions, target::setIgnoreAuthorPermissions); copyIfSet(src::getPreflightCommit, target::setPreflightCommit); copyIfSet(src::getReadPermissionCheck, target::setReadPermissionCheck); copyIfSet(src::getGitMergeAvoidanceAfterChangeNum, target::setGitMergeAvoidanceAfterChangeNum); copyIfSet(src::getJobLookup, target::setJobLookup); copyIfSet(src::getDepotBranchCreationEnable, target::setDepotBranchCreationEnable); copyIfSet(src::getDepotBranchCreationP4group, target::setDepotBranchCreationP4group); copyIfSet(src::getDepotBranchCreationDepotPath, target::setDepotBranchCreationDepotPath); copyIfSet(src::getDepotBranchCreationView, target::setDepotBranchCreationView); copyIfSet(src::getEnableGitFindCopies, target::setEnableGitFindCopies); copyIfSet(src::getEnableGitFindRenames, target::setEnableGitFindRenames); copyIfSet(src::getEnableStreamImports, target::setEnableStreamImports); copyIfSet(src::getHttpUrl, target::setHttpUrl); copyIfSet(src::getSshUrl, target::setSshUrl); copyIfSet(src::getEmailCaseSensitivity, target::setEmailCaseSensitivity); copyIfSet(src::getAuthorSource, target::setAuthorSource); copyIfSet(src::getLimitSpaceMb, target::setLimitSpaceMb); copyIfSet(src::getLimitCommitsReceived, target::setLimitCommitsReceived); copyIfSet(src::getLimitFilesReceived, target::setLimitFilesReceived); copyIfSet(src::getLimitMegabytesReceived, target::setLimitMegabytesReceived); } default void updateBranchConfig(GitFusionRepoConfig repoConfig, GitFusionRepoBranchConfig src) { List<GitFusionRepoBranchConfig> branchConfigs = repoConfig.getBranches(); GitFusionRepoBranchConfig target = branchConfigs.stream().filter(c -> c.getGitBranchId().equals(src.getGitBranchId())).findFirst().orElse(null); if (target == null) { branchConfigs.add(src); } else { copyIfSet(src::getGitBranchName, target::setGitBranchName); copyIfSet(src::getView, target::setView); copyIfSet(src::getReadOnly, target::setReadOnly); copyIfSet(src::getStream, target::setStream); } } default <T> void copyIfSet(Supplier<T> supplier, Consumer<T> consumer) { T val = supplier.get(); if (val != null) { consumer.accept(val); } } default List<ResultMap> deleteGitFusionRepoConfig( Supplier<IServer> serverSupplier, String gitFusionDepot, String repoId, String changeDescription) throws IOException { String depotPath = String.format("//%s/repos/%s/p4gf_config", gitFusionDepot, repoId); if (hasSpecialChars(depotPath)) { throw new IllegalArgumentException("No wildcards allowed in repo " + "config locations"); } ChangelistRequest changelistRequest = new ChangelistRequest(); List<ChangelistAction> actions = new ArrayList<>(); ChangelistAction action = new ChangelistAction(); action.setActionType("delete"); action.setDepotFile(depotPath); actions.add(action); changelistRequest.setActions(actions); changelistRequest.setDescription(changeDescription); CreateChange createChange = new CreateChange(serverSupplier); return createChange.apply(changelistRequest); } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19535 | drobins | Refactor package names to hws | ||
//guest/perforce_software/helix-web-services/main/source/git_fusion/src/main/java/com/perforce/helix_web_services/git_fusion/GitFusionConfigMethods.java | |||||
#3 | 18905 | tjuricek |
Add Git Fusion environent configuration and testing, and altered the implementation to use the newly defined API. Note: only runs on linux. We use latest GF production for testing and GF packages are linux only. The "integration" is pretty "light" at this point. This does require the test machine to have our package repository setup. |
||
#2 | 18710 | tjuricek |
Convert change-related command models to our client API models, also, complete the "alpha" tagging of methods. This consolidates models related to creating changelists to come from the Java client SDK version. We are now tagging various methods as "alpha" to signify they may break in upcoming versions. This allows new features to have a period where they can be available, but not necessarily need to be supported in upcoming releases. |
||
#1 | 17177 | tjuricek |
Implement Git Fusion repository methods: /git-fusion/v1/repo Note: I've changed the JSON format (which is currently unused) because the older system did not allow for global overrides in the per-repository config section. |