Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add git-sync command #153

Closed
wants to merge 7 commits into from
@@ -62,7 +62,8 @@ images {
'git-info': 'org.openjdk.skara.cli/org.openjdk.skara.cli.GitInfo',
'git-translate': 'org.openjdk.skara.cli/org.openjdk.skara.cli.GitTranslate',
'git-skara': 'org.openjdk.skara.cli/org.openjdk.skara.cli.GitSkara',
'hg-openjdk-import': 'org.openjdk.skara.cli/org.openjdk.skara.cli.HgOpenJDKImport'
'hg-openjdk-import': 'org.openjdk.skara.cli/org.openjdk.skara.cli.HgOpenJDKImport',
'git-sync': 'org.openjdk.skara.cli/org.openjdk.skara.cli.GitSync'
]

ext.modules = ['jdk.crypto.ec']
@@ -29,7 +29,7 @@

import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.*;
import java.util.List;
import java.util.function.Supplier;
import java.util.logging.Level;
@@ -175,6 +175,14 @@ public static void main(String[] args) throws IOException {
upstreamUrl = "git+" + upstreamUrl;
}
repo.addRemote("upstream", upstreamUrl);
var gitConfig = repo.root().resolve(".git").resolve("config");
if (!isMercurial && Files.exists(gitConfig)) {
var lines = List.of(
"[sync]",
" remote = upstream"
);
Files.write(gitConfig, lines, StandardOpenOption.WRITE, StandardOpenOption.APPEND);
}
System.out.println("done");
} else {
System.out.println(webUrl);
@@ -212,46 +212,6 @@ private static void apply(Path patch) throws IOException {
await(pb.start());
}

private static URI toURI(String remotePath) throws IOException {
if (remotePath.startsWith("git+")) {
remotePath = remotePath.substring("git+".length());
}
if (remotePath.startsWith("http")) {
return URI.create(remotePath);
} else {
if (remotePath.startsWith("ssh://")) {
remotePath = remotePath.substring("ssh://".length()).replaceFirst("/", ":");
}
var indexOfColon = remotePath.indexOf(':');
var indexOfSlash = remotePath.indexOf('/');
if (indexOfColon != -1) {
if (indexOfSlash == -1 || indexOfColon < indexOfSlash) {
var path = remotePath.contains("@") ? remotePath.split("@")[1] : remotePath;
var name = path.split(":")[0];

// Could be a Host in the ~/.ssh/config file
var sshConfig = Path.of(System.getProperty("user.home"), ".ssh", "config");
if (Files.exists(sshConfig)) {
for (var host : SSHConfig.parse(sshConfig).hosts()) {
if (host.name().equals(name)) {
var hostName = host.hostName();
if (hostName != null) {
return URI.create("https://" + hostName + "/" + path.split(":")[1]);
}
}
}
}

// Otherwise is must be a domain
return URI.create("https://" + path.replace(":", "/"));
}
}
}

exit("error: cannot find remote repository for " + remotePath);
return null; // will never reach here
}

private static int longest(List<String> strings) {
return strings.stream().mapToInt(String::length).max().orElse(0);
}
@@ -347,7 +307,7 @@ public static void main(String[] args) throws IOException, InterruptedException
var remotePullPath = repo.pullPath(remote);
var username = arguments.contains("username") ? arguments.get("username").asString() : null;
var token = isMercurial ? System.getenv("HG_TOKEN") : System.getenv("GIT_TOKEN");
var uri = toURI(remotePullPath);
var uri = Remote.toWebURI(remotePullPath);
var credentials = GitCredentials.fill(uri.getHost(), uri.getPath(), username, token, uri.getScheme());
var host = Host.from(uri, new PersonalAccessToken(credentials.username(), credentials.password()));

@@ -116,6 +116,7 @@ public static void main(String[] args) throws Exception {
commands.put("token", GitToken::main);
commands.put("info", GitInfo::main);
commands.put("translate", GitTranslate::main);
commands.put("sync", GitSync::main);
commands.put("update", GitSkara::update);
commands.put("help", GitSkara::usage);

@@ -0,0 +1,182 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.skara.cli;

import org.openjdk.skara.args.*;
import org.openjdk.skara.vcs.*;

import java.io.*;
import java.net.URI;
import java.nio.file.*;
import java.util.*;
import java.util.logging.*;

public class GitSync {
private static IOException die(String message) {
System.err.println(message);
System.exit(1);
return new IOException("will never reach here");
}

private static int fetch() throws IOException, InterruptedException {
var pb = new ProcessBuilder("git", "fetch");
pb.inheritIO();
return pb.start().waitFor();
}

private static int pull() throws IOException, InterruptedException {
var pb = new ProcessBuilder("git", "pull");
pb.inheritIO();
return pb.start().waitFor();
}

public static void main(String[] args) throws IOException, InterruptedException {
var flags = List.of(
Option.shortcut("")
.fullname("from")
.describe("REMOTE")
.helptext("Fetch changes from this remote")
.optional(),
Option.shortcut("")
.fullname("to")
.describe("REMOTE")
.helptext("Push changes to this remote")
.optional(),
Option.shortcut("")
.fullname("branches")
.describe("BRANCHES")
.helptext("Comma separated list of branches to sync")
.optional(),
Switch.shortcut("")
.fullname("pull")
.helptext("Pull current branch from origin after successful sync")
.optional(),
Switch.shortcut("")
.fullname("fetch")
.helptext("Fetch current branch from origin after successful sync")
.optional(),
Switch.shortcut("m")
.fullname("mercurial")
.helptext("Force use of mercurial")
.optional(),
Switch.shortcut("")
.fullname("verbose")
.helptext("Turn on verbose output")
.optional(),
Switch.shortcut("")
.fullname("debug")
.helptext("Turn on debugging output")
.optional(),
Switch.shortcut("v")
.fullname("version")
.helptext("Print the version of this tool")
.optional()
);

var parser = new ArgumentParser("git sync", flags);
var arguments = parser.parse(args);

if (arguments.contains("version")) {
System.out.println("git-sync version: " + Version.fromManifest().orElse("unknown"));
System.exit(0);
}

if (arguments.contains("verbose") || arguments.contains("debug")) {
var level = arguments.contains("debug") ? Level.FINER : Level.FINE;
Logging.setup(level);
}

var cwd = Paths.get("").toAbsolutePath();
var repo = Repository.get(cwd).orElseThrow(() ->
die("error: no repository found at " + cwd.toString())
);

var remotes = repo.remotes();

String upstream = null;
if (arguments.contains("from")) {
upstream = arguments.get("from").asString();
} else {
var lines = repo.config("sync.from");
if (lines.size() == 1 && remotes.contains(lines.get(0))) {
upstream = lines.get(0);
} else {
die("No remote provided to fetch from, please set the --from flag");
}
}
var upstreamPullPath = remotes.contains(upstream) ?
Remote.toURI(repo.pullPath(upstream)) : URI.create(upstream);

String origin = null;
if (arguments.contains("to")) {
origin = arguments.get("to").asString();
} else {
var lines = repo.config("sync.to");
if (lines.size() == 1) {
if (!remotes.contains(lines.get(0))) {
die("The given remote to push to, " + lines.get(0) + ", does not exist");
} else {
origin = lines.get(0);
}
} else {
origin = "origin";
}
}
var originPushPath = Remote.toURI(repo.pushPath(origin));

var branches = new HashSet<String>();
if (arguments.contains("branches")) {
var requested = arguments.get("branches").asString().split(",");
for (var branch : requested) {
branches.add(branch.trim());
}
}

for (var branch : repo.remoteBranches(upstream)) {
var name = branch.name();
if (!branches.isEmpty() && !branches.contains(name)) {
System.out.println("Skipping branch " + name);
continue;
}
System.out.print("Syncing " + upstream + "/" + name + " to " + origin + "/" + name + "... ");

This comment has been minimized.

@rwestberg

rwestberg Sep 24, 2019 Member

Do you need to flush the PrintStream here?

This comment has been minimized.

@edvbld

edvbld Sep 24, 2019 Author Member

Probably, good idea, let me fix!

System.out.flush();
var fetchHead = repo.fetch(upstreamPullPath, branch.hash().hex());
repo.push(fetchHead, originPushPath, name);
System.out.println("done");
}

if (arguments.contains("fetch")) {
int err = fetch();
if (err != 0) {
System.exit(err);
}
}

if (arguments.contains("pull")) {
int err = pull();
if (err != 0) {
System.exit(err);
}
}
}
}
@@ -0,0 +1,117 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.skara.cli;

import org.openjdk.skara.ssh.SSHConfig;

import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Files;

class Remote {
public static URI toWebURI(String remotePath) throws IOException {
if (remotePath.startsWith("git+")) {
remotePath = remotePath.substring("git+".length());
}
if (remotePath.startsWith("http")) {
return URI.create(remotePath);
} else {
if (remotePath.startsWith("ssh://")) {
remotePath = remotePath.substring("ssh://".length()).replaceFirst("/", ":");
}
var indexOfColon = remotePath.indexOf(':');
var indexOfSlash = remotePath.indexOf('/');
if (indexOfColon != -1) {
if (indexOfSlash == -1 || indexOfColon < indexOfSlash) {
var path = remotePath.contains("@") ? remotePath.split("@")[1] : remotePath;
var name = path.split(":")[0];

// Could be a Host in the ~/.ssh/config file
var sshConfig = Path.of(System.getProperty("user.home"), ".ssh", "config");
if (Files.exists(sshConfig)) {
for (var host : SSHConfig.parse(sshConfig).hosts()) {
if (host.name().equals(name)) {
var hostName = host.hostName();
if (hostName != null) {
return URI.create("https://" + hostName + "/" + path.split(":")[1]);
}
}
}
}

// Otherwise is must be a domain
return URI.create("https://" + path.replace(":", "/"));
}
}
}

throw new IOException("error: cannot find remote repository for " + remotePath);
}

public static URI toURI(String remotePath) throws IOException {
if (remotePath.startsWith("git+")) {
remotePath = remotePath.substring("git+".length());
}
if (remotePath.startsWith("http://") ||
remotePath.startsWith("https://") ||
remotePath.startsWith("ssh://") ||
remotePath.startsWith("file://") ||
remotePath.startsWith("git://")) {
return URI.create(remotePath);
}

var indexOfColon = remotePath.indexOf(':');
var indexOfSlash = remotePath.indexOf('/');
if (indexOfColon != -1) {
if (indexOfSlash == -1 || indexOfColon < indexOfSlash) {
var path = remotePath.contains("@") ? remotePath.split("@")[1] : remotePath;
var name = path.split(":")[0];

// Could be a Host in the ~/.ssh/config file
var sshConfig = Path.of(System.getProperty("user.home"), ".ssh", "config");
if (Files.exists(sshConfig)) {
for (var host : SSHConfig.parse(sshConfig).hosts()) {
if (host.name().equals(name)) {
var hostName = host.hostName();
if (hostName != null) {
var username = host.user();
if (username == null) {
username = remotePath.contains("@") ? remotePath.split("@")[0] : null;
}
var userPrefix = username == null ? "" : username + "@";
return URI.create("ssh://" + userPrefix + hostName + "/" + path.split(":")[1]);
}
}
}
}

// Otherwise is must be a domain
var userPrefix = remotePath.contains("@") ? remotePath.split("@")[0] + "@" : "";
return URI.create("ssh://" + userPrefix + path.replace(":", "/"));
}
}

throw new IOException("error: cannot construct proper URI for " + remotePath);
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.