in java/com/googlesource/gerrit/plugins/supermanifest/JiriUpdater.java [62:201]
private void updateSubmodules(
Repository repo,
String targetRef,
URI targetURI,
JiriProjects projects,
GerritRemoteReader reader)
throws IOException, GitAPIException {
DirCache index = DirCache.newInCore();
DirCacheBuilder builder = index.builder();
ObjectInserter inserter = repo.newObjectInserter();
try (RevWalk rw = new RevWalk(repo)) {
Config cfg = new Config();
projects.sortByPath();
String parent = null;
for (JiriProjects.Project proj : projects.getProjects()) {
String path = proj.getPath();
String nameUri = proj.getRemote();
if (parent != null) {
String p1 = StringUtil.stripAndAddCharsAtEnd(path, "/");
String p2 = StringUtil.stripAndAddCharsAtEnd(parent, "/");
if (p1.startsWith(p2)) {
warn(
"Skipping project %s(%s) as git doesn't support nested submodules",
proj.getName(), path);
continue;
}
}
ObjectId objectId;
String ref = proj.getRef();
if (ObjectId.isId(ref)) {
objectId = ObjectId.fromString(ref);
} else {
objectId = reader.sha1(nameUri, ref);
if (objectId == null) {
warn("failed to get ref '%s' for '%s', skipping", ref, nameUri);
continue;
}
}
// can be branch, tag or SHA1 (objectId)
if (!ObjectId.isId(ref)) {
// "branch" field is only for non-tag references.
// Keep tags in "ref" field as hint for other tools.
String field = ref.startsWith(REFS_TAGS) ? "ref" : "branch";
cfg.setString("submodule", path, field, ref);
}
if (proj.getHistorydepth() > 0) {
cfg.setBoolean("submodule", path, "shallow", true);
if (proj.getHistorydepth() != 1) {
warn(
"Project %s(%s) has historydepth other than 1. Submodule only support shallow of depth 1.",
proj.getName(), proj.getPath());
}
}
URI submodUrl = URI.create(nameUri);
// check if repo is local by matching hostnames
String repoName = submodUrl.getPath();
while (repoName.startsWith("/")) {
repoName = repoName.substring(1);
}
URI localURI = getLocalURI(repoName);
if (localURI != null && localURI.getHost().equals(submodUrl.getHost())) {
submodUrl = relativize(targetURI, URI.create(repoName));
}
cfg.setString("submodule", path, "path", path);
cfg.setString("submodule", path, "url", submodUrl.toString());
// create gitlink
DirCacheEntry dcEntry = new DirCacheEntry(path);
dcEntry.setObjectId(objectId);
dcEntry.setFileMode(FileMode.GITLINK);
builder.add(dcEntry);
parent = path;
}
String content = cfg.toText();
// create a new DirCacheEntry for .gitmodules file.
final DirCacheEntry dcEntry = new DirCacheEntry(Constants.DOT_GIT_MODULES);
ObjectId objectId = inserter.insert(Constants.OBJ_BLOB, content.getBytes(UTF_8));
dcEntry.setObjectId(objectId);
dcEntry.setFileMode(FileMode.REGULAR_FILE);
builder.add(dcEntry);
builder.finish();
ObjectId treeId = index.writeTree(inserter);
// Create a Commit object, populate it and write it
ObjectId headId = repo.resolve(targetRef + "^{commit}");
CommitBuilder commit = new CommitBuilder();
commit.setTreeId(treeId);
if (headId != null) commit.setParentIds(headId);
PersonIdent author =
new PersonIdent(
serverIdent.getName(),
serverIdent.getEmailAddress(),
new Date(),
serverIdent.getTimeZone());
commit.setAuthor(author);
commit.setCommitter(author);
commit.setMessage(RepoText.get().repoCommitMessage);
ObjectId commitId = inserter.insert(commit);
inserter.flush();
RefUpdate ru = repo.updateRef(targetRef);
ru.setNewObjectId(commitId);
ru.setExpectedOldObjectId(headId != null ? headId : ObjectId.zeroId());
Result rc = ru.update(rw);
switch (rc) {
case NEW:
case FORCED:
case FAST_FORWARD:
// Successful. Do nothing.
break;
case REJECTED:
case LOCK_FAILURE:
throw new ConcurrentRefUpdateException(
MessageFormat.format(JGitText.get().cannotLock, targetRef), ru.getRef(), rc);
case IO_FAILURE:
case NOT_ATTEMPTED:
case NO_CHANGE:
case REJECTED_CURRENT_BRANCH:
case REJECTED_MISSING_OBJECT:
case REJECTED_OTHER_REASON:
case RENAMED:
default:
throw new JGitInternalException(
MessageFormat.format(
JGitText.get().updatingRefFailed, targetRef, commitId.name(), rc));
}
}
}