1 /*
  2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 package org.openjdk.skara.bots.hgbridge;
 24 
 25 import org.openjdk.skara.forge.HostedRepository;
 26 import org.openjdk.skara.json.*;
 27 import org.openjdk.skara.vcs.*;
 28 import org.openjdk.skara.vcs.openjdk.convert.*;
 29 
 30 import java.io.IOException;
 31 import java.net.URI;
 32 import java.nio.charset.StandardCharsets;
 33 import java.nio.file.*;
 34 import java.util.*;
 35 import java.util.stream.Collectors;
 36 
 37 class ExporterConfig {
 38     private List<HostedRepository> destinations;
 39     private URI source;
 40     private HostedRepository configurationRepo;
 41     private String configurationRef;
 42     private HostedRepository marksRepo;
 43     private String marksRef;
 44     private String marksAuthorName;
 45     private String marksAuthorEmail;
 46     private List<String> replacementsFile;
 47     private List<String> correctionsFile;
 48     private List<String> lowercaseFile;
 49     private List<String> punctuatedFile;
 50     private List<String> authorsFile;
 51     private List<String> contributorsFile;
 52     private List<String> sponsorsFile;
 53 
 54     void destinations(List<HostedRepository> destinations) {
 55         this.destinations = destinations;
 56     }
 57 
 58     List<HostedRepository> destinations() {
 59         return new ArrayList<>(destinations);
 60     }
 61 
 62     void source(URI source) {
 63         this.source = source;
 64     }
 65 
 66     URI source() {
 67         return source;
 68     }
 69 
 70     void configurationRepo(HostedRepository configurationRepo) {
 71         this.configurationRepo = configurationRepo;
 72     }
 73 
 74     void configurationRef(String configurationRef) {
 75         this.configurationRef = configurationRef;
 76     }
 77 
 78     void marksRepo(HostedRepository marksRepo) {
 79         this.marksRepo = marksRepo;
 80     }
 81 
 82     HostedRepository marksRepo() {
 83         return marksRepo;
 84     }
 85 
 86     void marksRef(String marksRef) {
 87         this.marksRef = marksRef;
 88     }
 89 
 90     String marksRef() {
 91         return marksRef;
 92     }
 93 
 94     void marksAuthorName(String marksAuthorName) {
 95         this.marksAuthorName = marksAuthorName;
 96     }
 97 
 98     String marksAuthorName() {
 99         return marksAuthorName;
100     }
101 
102     void marksAuthorEmail(String marksAuthorEmail) {
103         this.marksAuthorEmail = marksAuthorEmail;
104     }
105 
106     String marksAuthorEmail() {
107         return marksAuthorEmail;
108     }
109 
110     void replacements(List<String> replacements) {
111         replacementsFile = replacements;
112     }
113 
114     void corrections(List<String> corrections) {
115         correctionsFile = corrections;
116     }
117 
118     void lowercase(List<String> lowercase) {
119         lowercaseFile = lowercase;
120     }
121 
122     void punctuated(List<String> punctuated) {
123         punctuatedFile = punctuated;
124     }
125 
126     void authors(List<String> authors) {
127         authorsFile = authors;
128     }
129 
130     void contributors(List<String> contributors) {
131         contributorsFile = contributors;
132     }
133 
134     void sponsors(List<String> sponsors) {
135         sponsorsFile = sponsors;
136     }
137 
138     private interface FieldParser<T> {
139         T parse(JSONObject.Field value);
140     }
141 
142     private <K, V> Map<K, V> parseMap(Path base, List<String> files, FieldParser<K> keyParser, FieldParser<V> valueParser) throws IOException {
143         var ret = new HashMap<K, V>();
144         for (var file : files) {
145             var jsonData = Files.readString(base.resolve(file), StandardCharsets.UTF_8);
146             var json = JSON.parse(jsonData);
147             for (var field : json.fields()) {
148                 ret.put(keyParser.parse(field), valueParser.parse(field));
149             }
150         }
151         return ret;
152     }
153 
154     private interface ValueParser<T> {
155         T parse(JSONValue value);
156     }
157 
158     private <E> Set<E> parseCommits(Path base, List<String> files, ValueParser<E> valueParser) throws IOException {
159         var ret = new HashSet<E>();
160         for (var file : files) {
161             var jsonData = Files.readString(base.resolve(file), StandardCharsets.UTF_8);
162             var json = JSON.parse(jsonData);
163             for (var value : json.get("commits").asArray()) {
164                 ret.add(valueParser.parse(value));
165             }
166         }
167         return ret;
168     }
169 
170     public Converter resolve(Path scratchPath) throws IOException {
171         var localRepo = Repository.materialize(scratchPath, configurationRepo.url(),
172                                                configurationRef + ":hgbridge_config_" + configurationRepo.name());
173 
174         var replacements = parseMap(localRepo.root(), replacementsFile,
175                                     field -> new Hash(field.name()),
176                                     field -> field.value().stream()
177                                                   .map(JSONValue::asString).collect(Collectors.toList()));
178         var corrections = parseMap(localRepo.root(), correctionsFile,
179                                    field -> new Hash(field.name()),
180                                    field -> field.value().fields().stream()
181                                                  .collect(Collectors.toMap(JSONObject.Field::name, sub -> sub.value().asString())));
182         var lowercase = parseCommits(localRepo.root(), lowercaseFile, value -> new Hash(value.asString()));
183         var punctuated = parseCommits(localRepo.root(), punctuatedFile, value -> new Hash(value.asString()));
184         var authors = parseMap(localRepo.root(), authorsFile, JSONObject.Field::name, field -> field.value().asString());
185         var contributors = parseMap(localRepo.root(), contributorsFile, JSONObject.Field::name, field -> field.value().asString());
186         var sponsors = parseMap(localRepo.root(), sponsorsFile,
187                                 JSONObject.Field::name,
188                                 field -> field.value().stream()
189                                               .map(JSONValue::asString)
190                                               .collect(Collectors.toList()));
191 
192         return new HgToGitConverter(replacements, corrections, lowercase, punctuated, authors, contributors, sponsors);
193     }
194 }