mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-26 00:29:20 +08:00
Move libgit2 code to git_bindings repo
We now have a much clearer separation between Git code and this app specific code. This is awesome, it will allow other people to easily integrate Git within their apps. Also, eventually it will be trivial to switch to another implemention of Git (via JGit or a git client written completely in Dart) This breaks the iOS version as I haven't moved the code to build the ios version. Maybe this will be a good excuse for me to setup a proper CI/CD system for ios builds. There is also a chance this breaks Crashalytics NDK symbols :(
This commit is contained in:
@ -5,9 +5,6 @@ jobs:
|
||||
- image: vhanda/flutter-android:latest
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Get NDK Libraries
|
||||
command: apt-get update && apt-get install -y jq && ./scripts/download_ndk_libs.sh
|
||||
- run:
|
||||
name: Test
|
||||
command: flutter test
|
||||
|
@ -44,18 +44,6 @@ android {
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags ""
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
jniLibs.srcDirs = ['libs']
|
||||
java.srcDirs = ['src']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "app"
|
||||
@ -93,12 +81,6 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "src/main/cpp/CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
|
||||
dexOptions {
|
||||
preDexLibraries true
|
||||
jumboMode true
|
||||
@ -114,9 +96,6 @@ dependencies {
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.1.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
|
||||
|
||||
// For reading a file to string
|
||||
implementation 'commons-io:commons-io:2.5'
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
@ -50,5 +50,6 @@
|
||||
|
||||
<meta-data android:name="google_analytics_adid_collection_enabled" android:value="false" />
|
||||
<meta-data android:name="firebase_analytics_collection_enabled" android:value="false" />
|
||||
<meta-data android:name="flutterEmbedding" android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
@ -1,53 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
set(lib_src_DIR ${CMAKE_SOURCE_DIR}/../../../libs/${ANDROID_ABI})
|
||||
include_directories(
|
||||
${lib_src_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/../../../../../gj_common/
|
||||
)
|
||||
|
||||
add_library(openssl-lib
|
||||
STATIC
|
||||
IMPORTED)
|
||||
|
||||
set_target_properties(openssl-lib
|
||||
PROPERTIES IMPORTED_LOCATION
|
||||
${lib_src_DIR}/lib/libssl.a)
|
||||
|
||||
add_library(crypto-lib
|
||||
STATIC
|
||||
IMPORTED)
|
||||
|
||||
set_target_properties(crypto-lib
|
||||
PROPERTIES IMPORTED_LOCATION
|
||||
${lib_src_DIR}/lib/libcrypto.a)
|
||||
|
||||
add_library(ssh2-lib
|
||||
STATIC
|
||||
IMPORTED)
|
||||
|
||||
set_target_properties(ssh2-lib
|
||||
PROPERTIES IMPORTED_LOCATION
|
||||
${lib_src_DIR}/lib/libssh2.a)
|
||||
|
||||
add_library(git2-lib
|
||||
STATIC
|
||||
IMPORTED)
|
||||
|
||||
set_target_properties(git2-lib
|
||||
PROPERTIES IMPORTED_LOCATION
|
||||
${lib_src_DIR}/lib/libgit2.a)
|
||||
|
||||
add_library(native-lib
|
||||
SHARED
|
||||
${CMAKE_SOURCE_DIR}/../../../../../gj_common/gitjournal.c
|
||||
${CMAKE_SOURCE_DIR}/../../../../../gj_common/keygen.c
|
||||
${CMAKE_SOURCE_DIR}/../../../../../gj_common/common.c
|
||||
git.c
|
||||
)
|
||||
|
||||
target_compile_options(native-lib PRIVATE -Werror -Wall -Wextra -Wno-missing-field-initializers)
|
||||
|
||||
# The order of these libraries is super dooper important
|
||||
# Otherwise you'll get linker errors
|
||||
target_link_libraries(native-lib git2-lib ssh2-lib openssl-lib crypto-lib android log)
|
@ -1,199 +0,0 @@
|
||||
#include <jni.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "gitjournal.h"
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
void gj_log(const char *message) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "GitJournalLib", "%s", message);
|
||||
}
|
||||
|
||||
|
||||
jstring handle_error(JNIEnv *env, int err) {
|
||||
if (err != 0) {
|
||||
const gj_error *e = gj_error_info(err);
|
||||
if (e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "GitJournalLib", "Error %d/%d: %s\n", err,
|
||||
e->code, e->message);
|
||||
|
||||
jstring error = (*env)->NewStringUTF(env, e->message);
|
||||
gj_error_free(e);
|
||||
return error;
|
||||
}
|
||||
return (*env)->NewStringUTF(env, "Error");
|
||||
}
|
||||
|
||||
return (*env)->NewStringUTF(env, "");
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_setupLib(
|
||||
JNIEnv *env,
|
||||
jobject this_obj) {
|
||||
|
||||
UNUSED(env);
|
||||
UNUSED(this_obj);
|
||||
|
||||
gj_init();
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_init(
|
||||
JNIEnv *env,
|
||||
jobject this_obj,
|
||||
jstring jni_git_base_path) {
|
||||
UNUSED(this_obj);
|
||||
|
||||
const char *git_base_path = (*env)->GetStringUTFChars(env, jni_git_base_path, 0);
|
||||
|
||||
int err = gj_git_init(git_base_path);
|
||||
return handle_error(env, err);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_clone(
|
||||
JNIEnv *env,
|
||||
jobject this_obj,
|
||||
jstring jni_clone_url,
|
||||
jstring jni_git_base_path) {
|
||||
UNUSED(this_obj);
|
||||
const char *clone_url = (*env)->GetStringUTFChars(env, jni_clone_url, 0);
|
||||
const char *git_base_path = (*env)->GetStringUTFChars(env, jni_git_base_path, 0);
|
||||
|
||||
int err = gj_git_clone(clone_url, git_base_path);
|
||||
return handle_error(env, err);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_pull(
|
||||
JNIEnv *env,
|
||||
jobject this_obj,
|
||||
jstring jni_git_base_path,
|
||||
jstring jni_author_name,
|
||||
jstring jni_author_email) {
|
||||
UNUSED(this_obj);
|
||||
const char *git_base_path = (*env)->GetStringUTFChars(env, jni_git_base_path, 0);
|
||||
const char *author_name = (*env)->GetStringUTFChars(env, jni_author_name, 0);
|
||||
const char *author_email = (*env)->GetStringUTFChars(env, jni_author_email, 0);
|
||||
|
||||
int err = gj_git_pull(git_base_path, author_name, author_email);
|
||||
return handle_error(env, err);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_push(
|
||||
JNIEnv *env,
|
||||
jobject this_obj,
|
||||
jstring jni_git_base_path) {
|
||||
UNUSED(this_obj);
|
||||
const char *git_base_path = (*env)->GetStringUTFChars(env, jni_git_base_path, 0);
|
||||
|
||||
int err = gj_git_push(git_base_path);
|
||||
return handle_error(env, err);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_commit(
|
||||
JNIEnv *env,
|
||||
jobject this_obj,
|
||||
jstring jni_git_base_path,
|
||||
jstring jni_author_name,
|
||||
jstring jni_author_email,
|
||||
jstring jni_message) {
|
||||
UNUSED(this_obj);
|
||||
const char *git_base_path = (*env)->GetStringUTFChars(env, jni_git_base_path, 0);
|
||||
const char *author_name = (*env)->GetStringUTFChars(env, jni_author_name, 0);
|
||||
const char *author_email = (*env)->GetStringUTFChars(env, jni_author_email, 0);
|
||||
const char *message = (*env)->GetStringUTFChars(env, jni_message, 0);
|
||||
|
||||
int err = gj_git_commit(git_base_path, author_name, author_email, message, 0, 0);
|
||||
return handle_error(env, err);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_resetHard(
|
||||
JNIEnv *env,
|
||||
jobject this_obj,
|
||||
jstring jni_git_base_path,
|
||||
jstring jni_ref) {
|
||||
UNUSED(this_obj);
|
||||
const char *git_base_path = (*env)->GetStringUTFChars(env, jni_git_base_path, 0);
|
||||
const char *ref = (*env)->GetStringUTFChars(env, jni_ref, 0);
|
||||
|
||||
int err = gj_git_reset_hard(git_base_path, ref);
|
||||
return handle_error(env, err);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_add(
|
||||
JNIEnv *env,
|
||||
jobject this_obj,
|
||||
jstring jni_git_base_path,
|
||||
jstring jni_add_pattern) {
|
||||
UNUSED(this_obj);
|
||||
|
||||
const char *git_base_path = (*env)->GetStringUTFChars(env, jni_git_base_path, 0);
|
||||
const char *add_pattern = (*env)->GetStringUTFChars(env, jni_add_pattern, 0);
|
||||
|
||||
int err = gj_git_add(git_base_path, add_pattern);
|
||||
return handle_error(env, err);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_rm(
|
||||
JNIEnv *env,
|
||||
jobject this_obj,
|
||||
jstring jni_git_base_path,
|
||||
jstring jni_pattern) {
|
||||
UNUSED(this_obj);
|
||||
|
||||
const char *git_base_path = (*env)->GetStringUTFChars(env, jni_git_base_path, 0);
|
||||
const char *pattern = (*env)->GetStringUTFChars(env, jni_pattern, 0);
|
||||
|
||||
int err = gj_git_rm(git_base_path, pattern);
|
||||
return handle_error(env, err);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_setSshKeys(
|
||||
JNIEnv *env,
|
||||
jobject this_obj,
|
||||
jstring jni_public_key_path,
|
||||
jstring jni_private_key_path,
|
||||
jstring jni_passphrase) {
|
||||
UNUSED(this_obj);
|
||||
|
||||
const char *public_key_path = (*env)->GetStringUTFChars(env, jni_public_key_path, 0);
|
||||
const char *private_key_path = (*env)->GetStringUTFChars(env, jni_private_key_path, 0);
|
||||
const char *passphrase = (*env)->GetStringUTFChars(env, jni_passphrase, 0);
|
||||
|
||||
gj_set_ssh_keys_paths((char *) public_key_path, (char *) private_key_path, (char *) passphrase);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_io_gitjournal_gitjournal_Git_generateKeys(
|
||||
JNIEnv *env,
|
||||
jobject this_obj,
|
||||
jstring jni_private_key_path,
|
||||
jstring jni_public_key_path,
|
||||
jstring jni_comment) {
|
||||
UNUSED(this_obj);
|
||||
|
||||
const char *private_key_path = (*env)->GetStringUTFChars(env, jni_private_key_path, 0);
|
||||
const char *public_key_path = (*env)->GetStringUTFChars(env, jni_public_key_path, 0);
|
||||
const char *comment = (*env)->GetStringUTFChars(env, jni_comment, 0);
|
||||
|
||||
int err = gj_generate_ssh_keys(private_key_path, public_key_path, comment);
|
||||
return handle_error(env, err);
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import io.flutter.plugin.common.MethodChannel.Result;
|
||||
|
||||
public class AnyThreadResult implements MethodChannel.Result {
|
||||
private Result result;
|
||||
|
||||
AnyThreadResult(Result r) {
|
||||
result = r;
|
||||
}
|
||||
|
||||
public void success(@Nullable Object var1) {
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
result.success(var1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void error(String var1, @Nullable String var2, @Nullable Object var3) {
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
result.error(var1, var2, var3);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void notImplemented() {
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
result.notImplemented();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class GenerateSSHKeysTask extends AsyncTask<String, Void, Void> {
|
||||
private final static String TAG = "GenerateSSHKeys";
|
||||
private AnyThreadResult result;
|
||||
|
||||
public GenerateSSHKeysTask(AnyThreadResult _result) {
|
||||
result = _result;
|
||||
}
|
||||
|
||||
protected Void doInBackground(String... params) {
|
||||
String keysDirPath = params[0];
|
||||
File keysDir = new File(keysDirPath);
|
||||
if (!keysDir.exists()) {
|
||||
keysDir.mkdir();
|
||||
}
|
||||
|
||||
String comment = params[1];
|
||||
|
||||
final String privateKeyPath = keysDir + "/id_rsa";
|
||||
final String publicKeyPath = keysDir + "/id_rsa.pub";
|
||||
|
||||
File privateKeyFile = new File(privateKeyPath);
|
||||
if (privateKeyFile.exists()) {
|
||||
Log.d(TAG, "Private key already exists. Overwriting");
|
||||
}
|
||||
|
||||
Git git = new Git();
|
||||
String errorStr = git.generateKeys(privateKeyPath, publicKeyPath, comment);
|
||||
if (!errorStr.isEmpty()) {
|
||||
result.error("FAILED", errorStr, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
String publicKey;
|
||||
try {
|
||||
publicKey = FileUtils.readFileToString(new File(publicKeyPath), Charset.defaultCharset());
|
||||
} catch (IOException ex) {
|
||||
Log.d(TAG, ex.toString());
|
||||
result.error("FAILED", "Failed to read the public key", null);
|
||||
return null;
|
||||
}
|
||||
|
||||
result.success(publicKey);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
public class Git {
|
||||
static {
|
||||
System.loadLibrary("native-lib");
|
||||
}
|
||||
|
||||
// This needs to be called once!
|
||||
public native void setupLib();
|
||||
|
||||
public native String generateKeys(String privateKeyPath, String publicKeyPath, String comment);
|
||||
|
||||
public native String init(String basePath);
|
||||
public native String clone(String cloneUrl, String basePath);
|
||||
|
||||
public native String pull(String basePath, String authorName, String authorEmail);
|
||||
public native String push(String basePath);
|
||||
|
||||
public native String commit(String basePath, String authorName, String authorEmail, String message);
|
||||
public native String resetHard(String basePath, String ref);
|
||||
public native String add(String basePath, String pattern);
|
||||
public native String rm(String basePath, String pattern);
|
||||
|
||||
public native void setSshKeys(String publicKeyPath, String privateKeyPath, String passphrase);
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
public class GitAddTask extends AsyncTask<String, Void, Void> {
|
||||
private final static String TAG = "GitAdd";
|
||||
private AnyThreadResult result;
|
||||
|
||||
public GitAddTask(AnyThreadResult _result) {
|
||||
result = _result;
|
||||
}
|
||||
|
||||
protected Void doInBackground(String... params) {
|
||||
final String cloneDirPath = params[0];
|
||||
final String filePattern = params[1];
|
||||
|
||||
Git git = new Git();
|
||||
String errorStr = git.add(cloneDirPath, filePattern);
|
||||
if (!errorStr.isEmpty()) {
|
||||
result.error("FAILED", errorStr, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
result.success(null);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class GitCloneTask extends AsyncTask<String, Void, Void> {
|
||||
private final static String TAG = "GitClone";
|
||||
private AnyThreadResult result;
|
||||
|
||||
public GitCloneTask(AnyThreadResult _result) {
|
||||
result = _result;
|
||||
}
|
||||
|
||||
protected Void doInBackground(String... params) {
|
||||
String url = params[0];
|
||||
String cloneDirPath = params[1];
|
||||
final String publicKeyPath = params[2];
|
||||
final String privateKeyPath = params[3];
|
||||
|
||||
File cloneDir = new File(cloneDirPath);
|
||||
|
||||
Git git = new Git();
|
||||
git.setSshKeys(publicKeyPath, privateKeyPath, "");
|
||||
|
||||
String errorStr = git.clone(url, cloneDirPath);
|
||||
if (!errorStr.isEmpty()) {
|
||||
result.error("FAILED", errorStr, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
result.success(null);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class GitCommitTask extends AsyncTask<String, Void, Void> {
|
||||
private final static String TAG = "GitCommit";
|
||||
private AnyThreadResult result;
|
||||
|
||||
public GitCommitTask(AnyThreadResult _result) {
|
||||
result = _result;
|
||||
}
|
||||
|
||||
protected Void doInBackground(String... params) {
|
||||
final String cloneDirPath = params[0];
|
||||
final String authorName = params[1];
|
||||
final String authorEmail = params[2];
|
||||
final String message = params[3];
|
||||
final String commitDateTimeStr = params[4];
|
||||
|
||||
File cloneDir = new File(cloneDirPath);
|
||||
|
||||
Git git = new Git();
|
||||
String errorStr = git.commit(cloneDirPath, authorName, authorEmail, message);
|
||||
if (!errorStr.isEmpty()) {
|
||||
result.error("FAILED", errorStr, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
result.success(null);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
public class GitInitTask extends AsyncTask<String, Void, Void> {
|
||||
private final static String TAG = "GitInit";
|
||||
private AnyThreadResult result;
|
||||
|
||||
public GitInitTask(AnyThreadResult _result) {
|
||||
result = _result;
|
||||
}
|
||||
|
||||
protected Void doInBackground(String... params) {
|
||||
String cloneDirPath = params[0];
|
||||
|
||||
Git git = new Git();
|
||||
String errorStr = git.init(cloneDirPath);
|
||||
if (!errorStr.isEmpty()) {
|
||||
result.error("FAILED", errorStr, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
result.success(null);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
public class GitPullTask extends AsyncTask<String, Void, Void> {
|
||||
private final static String TAG = "GitPull";
|
||||
private AnyThreadResult result;
|
||||
|
||||
public GitPullTask(AnyThreadResult _result) {
|
||||
result = _result;
|
||||
}
|
||||
|
||||
protected Void doInBackground(String... params) {
|
||||
String cloneDirPath = params[0];
|
||||
final String publicKeyPath = params[1];
|
||||
final String privateKeyPath = params[2];
|
||||
final String authorName = params[3];
|
||||
final String authorEmail = params[4];
|
||||
|
||||
Git git = new Git();
|
||||
git.setSshKeys(publicKeyPath, privateKeyPath, "");
|
||||
String errorStr = git.pull(cloneDirPath, authorName, authorEmail);
|
||||
if (!errorStr.isEmpty()) {
|
||||
result.error("FAILED", errorStr, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
result.success(null);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
public class GitPushTask extends AsyncTask<String, Void, Void> {
|
||||
private final static String TAG = "GitPush";
|
||||
private AnyThreadResult result;
|
||||
|
||||
public GitPushTask(AnyThreadResult _result) {
|
||||
result = _result;
|
||||
}
|
||||
|
||||
protected Void doInBackground(String... params) {
|
||||
String cloneDirPath = params[0];
|
||||
final String publicKeyPath = params[1];
|
||||
final String privateKeyPath = params[2];
|
||||
|
||||
Git git = new Git();
|
||||
git.setSshKeys(publicKeyPath, privateKeyPath, "");
|
||||
String errorStr = git.push(cloneDirPath);
|
||||
if (!errorStr.isEmpty()) {
|
||||
result.error("FAILED", errorStr, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
result.success(null);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
public class GitResetLastTask extends AsyncTask<String, Void, Void> {
|
||||
private final static String TAG = "GitResetLastTask";
|
||||
private AnyThreadResult result;
|
||||
|
||||
public GitResetLastTask(AnyThreadResult _result) {
|
||||
result = _result;
|
||||
}
|
||||
|
||||
protected Void doInBackground(String... params) {
|
||||
final String cloneDirPath = params[0];
|
||||
|
||||
Git git = new Git();
|
||||
String errorStr = git.resetHard(cloneDirPath, "HEAD^");
|
||||
if (!errorStr.isEmpty()) {
|
||||
result.error("FAILED", errorStr, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
result.success(null);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class GitRmTask extends AsyncTask<String, Void, Void> {
|
||||
private final static String TAG = "GitRm";
|
||||
private AnyThreadResult result;
|
||||
|
||||
public GitRmTask(AnyThreadResult _result) {
|
||||
result = _result;
|
||||
}
|
||||
|
||||
protected Void doInBackground(String... params) {
|
||||
final String cloneDirPath = params[0];
|
||||
final String filePattern = params[1];
|
||||
|
||||
File cloneDir = new File(cloneDirPath);
|
||||
|
||||
Git git = new Git();
|
||||
String errorStr = git.rm(cloneDirPath, filePattern);
|
||||
if (!errorStr.isEmpty()) {
|
||||
result.error("FAILED", errorStr, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
result.success(null);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,19 +1,18 @@
|
||||
package io.gitjournal.gitjournal;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
|
||||
import io.flutter.app.FlutterActivity;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||
@ -21,31 +20,25 @@ import io.flutter.plugin.common.MethodChannel.Result;
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant;
|
||||
import io.flutter.util.PathUtils;
|
||||
|
||||
// For MethodChannel
|
||||
import io.flutter.embedding.android.FlutterActivity;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
|
||||
public class MainActivity extends FlutterActivity implements MethodCallHandler {
|
||||
private static final String CHANNEL_NAME = "gitjournal.io/git";
|
||||
static MethodChannel channel;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
GeneratedPluginRegistrant.registerWith(this);
|
||||
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
|
||||
channel = new MethodChannel(getFlutterView(), CHANNEL_NAME);
|
||||
channel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_NAME);
|
||||
channel.setMethodCallHandler(this);
|
||||
|
||||
Git g = new Git();
|
||||
g.setupLib();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodCall(MethodCall call, Result result) {
|
||||
Context context = getApplicationContext();
|
||||
final String filesDir = PathUtils.getFilesDir(context);
|
||||
final String sshKeysLocation = filesDir + "/ssh";
|
||||
final String privateKeyPath = sshKeysLocation + "/id_rsa";
|
||||
final String publicKeyPath = sshKeysLocation + "/id_rsa.pub";
|
||||
|
||||
Log.d("GitJournalAndroid", "Called method " + call.method);
|
||||
if (call.arguments instanceof Map) {
|
||||
@ -63,182 +56,6 @@ public class MainActivity extends FlutterActivity implements MethodCallHandler {
|
||||
if (call.method.equals("getBaseDirectory")) {
|
||||
result.success(filesDir);
|
||||
return;
|
||||
} else if (call.method.equals("gitClone")) {
|
||||
String cloneUrl = call.argument("cloneUrl");
|
||||
String folderPath = call.argument("folderPath");
|
||||
|
||||
if (cloneUrl == null || cloneUrl.isEmpty()) {
|
||||
result.error("Invalid Parameters", "cloneUrl Invalid", null);
|
||||
return;
|
||||
}
|
||||
if (folderPath == null || folderPath.isEmpty()) {
|
||||
result.error("Invalid Parameters", "folderPath Invalid", null);
|
||||
return;
|
||||
}
|
||||
|
||||
AnyThreadResult anyResult = new AnyThreadResult(result);
|
||||
new GitCloneTask(anyResult).execute(cloneUrl, folderPath, publicKeyPath, privateKeyPath);
|
||||
return;
|
||||
} else if (call.method.equals("gitPull")) {
|
||||
String folderPath = call.argument("folderPath");
|
||||
String authorName = call.argument("authorName");
|
||||
String authorEmail = call.argument("authorEmail");
|
||||
|
||||
if (folderPath == null || folderPath.isEmpty()) {
|
||||
result.error("Invalid Parameters", "folderPath Invalid", null);
|
||||
return;
|
||||
}
|
||||
if (authorName == null || authorName.isEmpty()) {
|
||||
result.error("Invalid Parameters", "authorName Invalid", null);
|
||||
return;
|
||||
}
|
||||
if (authorEmail == null || authorEmail.isEmpty()) {
|
||||
result.error("Invalid Parameters", "authorEmail Invalid", null);
|
||||
return;
|
||||
}
|
||||
|
||||
AnyThreadResult anyResult = new AnyThreadResult(result);
|
||||
new GitPullTask(anyResult).execute(folderPath, publicKeyPath, privateKeyPath, authorName, authorEmail);
|
||||
return;
|
||||
} else if (call.method.equals("gitPush")) {
|
||||
String folderPath = call.argument("folderPath");
|
||||
|
||||
if (folderPath == null || folderPath.isEmpty()) {
|
||||
result.error("Invalid Parameters", "folderPath Invalid", null);
|
||||
return;
|
||||
}
|
||||
|
||||
AnyThreadResult anyResult = new AnyThreadResult(result);
|
||||
new GitPushTask(anyResult).execute(folderPath, publicKeyPath, privateKeyPath);
|
||||
return;
|
||||
} else if (call.method.equals("gitAdd")) {
|
||||
String folderPath = call.argument("folderPath");
|
||||
String filePattern = call.argument("filePattern");
|
||||
|
||||
if (folderPath == null || folderPath.isEmpty()) {
|
||||
result.error("Invalid Parameters", "folderPath Invalid", null);
|
||||
return;
|
||||
}
|
||||
if (filePattern == null || filePattern.isEmpty()) {
|
||||
result.error("Invalid Parameters", "filePattern Invalid", null);
|
||||
return;
|
||||
}
|
||||
|
||||
AnyThreadResult anyResult = new AnyThreadResult(result);
|
||||
new GitAddTask(anyResult).execute(folderPath, filePattern);
|
||||
return;
|
||||
} else if (call.method.equals("gitRm")) {
|
||||
String folderPath = call.argument("folderPath");
|
||||
String filePattern = call.argument("filePattern");
|
||||
|
||||
if (folderPath == null || folderPath.isEmpty()) {
|
||||
result.error("Invalid Parameters", "folderPath Invalid", null);
|
||||
return;
|
||||
}
|
||||
if (filePattern == null || filePattern.isEmpty()) {
|
||||
result.error("Invalid Parameters", "filePattern Invalid", null);
|
||||
return;
|
||||
}
|
||||
|
||||
AnyThreadResult anyResult = new AnyThreadResult(result);
|
||||
new GitRmTask(anyResult).execute(folderPath, filePattern);
|
||||
return;
|
||||
} else if (call.method.equals("gitCommit")) {
|
||||
String folderPath = call.argument("folderPath");
|
||||
String authorName = call.argument("authorName");
|
||||
String authorEmail = call.argument("authorEmail");
|
||||
String message = call.argument("message");
|
||||
String dateTimeStr = call.argument("when");
|
||||
|
||||
if (folderPath == null || folderPath.isEmpty()) {
|
||||
result.error("Invalid Parameters", "folderPath Invalid", null);
|
||||
return;
|
||||
}
|
||||
if (authorName == null || authorName.isEmpty()) {
|
||||
result.error("Invalid Parameters", "authorName Invalid", null);
|
||||
return;
|
||||
}
|
||||
if (authorEmail == null || authorEmail.isEmpty()) {
|
||||
result.error("Invalid Parameters", "authorEmail Invalid", null);
|
||||
return;
|
||||
}
|
||||
if (message == null || message.isEmpty()) {
|
||||
result.error("Invalid Parameters", "message Invalid", null);
|
||||
return;
|
||||
}
|
||||
|
||||
AnyThreadResult anyResult = new AnyThreadResult(result);
|
||||
new GitCommitTask(anyResult).execute(folderPath, authorName, authorEmail, message, dateTimeStr);
|
||||
return;
|
||||
} else if (call.method.equals("gitInit")) {
|
||||
String folderPath = call.argument("folderPath");
|
||||
|
||||
if (folderPath == null || folderPath.isEmpty()) {
|
||||
result.error("Invalid Parameters", "folderPath Invalid", null);
|
||||
return;
|
||||
}
|
||||
|
||||
AnyThreadResult anyResult = new AnyThreadResult(result);
|
||||
new GitInitTask(anyResult).execute(folderPath);
|
||||
return;
|
||||
} else if (call.method.equals("gitResetLast")) {
|
||||
String folderPath = call.argument("folderPath");
|
||||
|
||||
if (folderPath == null || folderPath.isEmpty()) {
|
||||
result.error("Invalid Parameters", "folderPath Invalid", null);
|
||||
return;
|
||||
}
|
||||
|
||||
AnyThreadResult anyResult = new AnyThreadResult(result);
|
||||
new GitResetLastTask(anyResult).execute(folderPath);
|
||||
return;
|
||||
} else if (call.method.equals("generateSSHKeys")) {
|
||||
String comment = call.argument("comment");
|
||||
if (comment == null || comment.isEmpty()) {
|
||||
Log.d("generateSSHKeys", "Defaulting to default comment");
|
||||
comment = "Generated on Android";
|
||||
}
|
||||
|
||||
AnyThreadResult anyResult = new AnyThreadResult(result);
|
||||
new GenerateSSHKeysTask(anyResult).execute(sshKeysLocation, comment);
|
||||
return;
|
||||
} else if (call.method.equals("getSSHPublicKey")) {
|
||||
String publicKey = "";
|
||||
try {
|
||||
publicKey = FileUtils.readFileToString(new File(publicKeyPath), Charset.defaultCharset());
|
||||
} catch (IOException ex) {
|
||||
Log.d("getSSHPublicKey", ex.toString());
|
||||
result.error("FAILED", "Failed to read the public key", null);
|
||||
return;
|
||||
}
|
||||
|
||||
result.success(publicKey);
|
||||
return;
|
||||
} else if (call.method.equals("setSshKeys")) {
|
||||
String privateKey = call.argument("privateKey");
|
||||
String publicKey = call.argument("publicKey");
|
||||
|
||||
if (privateKey == null || privateKey.isEmpty()) {
|
||||
result.error("Invalid Parameters", "privateKey Invalid", null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (publicKey == null || publicKey.isEmpty()) {
|
||||
result.error("Invalid Parameters", "publicKey Invalid", null);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
FileUtils.writeStringToFile(new File(publicKeyPath), publicKey, Charset.defaultCharset());
|
||||
FileUtils.writeStringToFile(new File(privateKeyPath), privateKey, Charset.defaultCharset());
|
||||
} catch (IOException ex) {
|
||||
Log.d("setSshKeys", ex.toString());
|
||||
result.error("FAILED", "Failed to write the ssh keys", null);
|
||||
return;
|
||||
}
|
||||
|
||||
result.success(publicKey);
|
||||
return;
|
||||
} else if (call.method.equals("dumpAppLogs")) {
|
||||
String filePath = filesDir + "/app-logs.txt";
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
test
|
||||
test.dSYM
|
||||
.vscode
|
3
gj_common/.gitignore
vendored
3
gj_common/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
test
|
||||
test.dSYM
|
||||
infer-out
|
@ -1,13 +0,0 @@
|
||||
FROM ubuntu:18.10
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV TZ Europe/Madrid
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y libssh2-1-dev curl gdb cppcheck xz-utils sudo libtinfo5
|
||||
RUN apt-get install -y cmake libssl-dev pkg-config zlib1g-dev clang tzdata git vim
|
||||
|
||||
COPY . /opt
|
||||
RUN /opt/install_infer.sh
|
||||
|
||||
RUN cd /opt && ./build-libgit2.sh
|
@ -1,16 +0,0 @@
|
||||
CC=clang
|
||||
|
||||
test: gitjournal.c test.c keygen.c common.c
|
||||
$(CC) -o test -g test.c common.c gitjournal.c keygen.c -lgit2 -lssl -lcrypto
|
||||
|
||||
build-env: Dockerfile
|
||||
docker build -t gitjournal_lib .
|
||||
|
||||
shell:
|
||||
docker run --rm -it -v `pwd`:/code -w /code gitjournal_lib bash
|
||||
|
||||
cppcheck:
|
||||
cppcheck --enable=all --suppress=unusedFunction common.c gitjournal.c keygen.c
|
||||
|
||||
infer:
|
||||
infer run -- make
|
@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eux
|
||||
|
||||
LIBGIT2_VERSION="0.28.1"
|
||||
if [ ! -f "libgit2.tar.gz" ]; then
|
||||
curl https://codeload.github.com/libgit2/libgit2/tar.gz/v${LIBGIT2_VERSION} -o libgit2.tar.gz
|
||||
fi
|
||||
|
||||
tar -xzf libgit2.tar.gz
|
||||
cd libgit2-${LIBGIT2_VERSION}
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake ../ \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error executing cmake"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cmake --build .
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error building"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
make install
|
@ -1,91 +0,0 @@
|
||||
#include "gitjournal.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <git2.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
void gj_log_internal(const char *format, ...)
|
||||
{
|
||||
char buffer[1024];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf(buffer, format, args);
|
||||
gj_log(buffer);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
gj_error *gj_error_info(int err)
|
||||
{
|
||||
if (err == 0)
|
||||
return NULL;
|
||||
|
||||
gj_error *error = (gj_error *)malloc(sizeof(gj_error));
|
||||
if (error == NULL)
|
||||
{
|
||||
gj_log_internal("Failed to allocate gj_error");
|
||||
return NULL;
|
||||
}
|
||||
error->message_allocated = false;
|
||||
if (err <= GJ_ERR_FIRST && err >= GJ_ERR_LAST)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case GJ_ERR_EMPTY_COMMIT:
|
||||
error->code = err;
|
||||
error->message = "Empty Commit";
|
||||
break;
|
||||
|
||||
case GJ_ERR_PULL_INVALID_STATE:
|
||||
error->code = err;
|
||||
error->message = "GitPull Invalid State";
|
||||
break;
|
||||
|
||||
case GJ_ERR_OPENSSL:
|
||||
error->code = ERR_peek_last_error();
|
||||
error->message_allocated = true;
|
||||
error->message = (char *)malloc(256);
|
||||
ERR_error_string(error->code, error->message);
|
||||
break;
|
||||
|
||||
case GJ_ERR_INVALID_CREDENTIALS:
|
||||
error->code = err;
|
||||
error->message = "Invalid Credentials";
|
||||
break;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
const git_error *e = git_error_last();
|
||||
if (e)
|
||||
{
|
||||
error->code = e->klass;
|
||||
error->message = (char *)malloc(strlen(e->message));
|
||||
if (error->message != NULL)
|
||||
{
|
||||
strcpy(error->message, e->message);
|
||||
error->message_allocated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
error->message = "Unknown Error - Malloc Failed";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error->code = 1000;
|
||||
error->message = "Unknown Message";
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void gj_error_free(const gj_error *err)
|
||||
{
|
||||
if (err->message_allocated)
|
||||
free(err->message);
|
||||
free((void *)err);
|
||||
}
|
@ -1,685 +0,0 @@
|
||||
#include "gitjournal.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <git2.h>
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
int match_cb(const char *path, const char *spec, void *payload)
|
||||
{
|
||||
UNUSED(spec);
|
||||
UNUSED(payload);
|
||||
|
||||
gj_log_internal("Add Match: %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gj_git_add(const char *git_base_path, const char *pattern)
|
||||
{
|
||||
int err;
|
||||
git_repository *repo = NULL;
|
||||
git_index *index = NULL;
|
||||
|
||||
err = git_repository_open(&repo, git_base_path);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_repository_index(&index, repo);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
char *paths[] = {(char *)pattern};
|
||||
git_strarray pathspec = {paths, 1};
|
||||
|
||||
err = git_index_add_all(index, &pathspec, GIT_INDEX_ADD_DEFAULT, match_cb, NULL);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_index_write(index);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
git_index_free(index);
|
||||
git_repository_free(repo);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int rm_match_cb(const char *path, const char *spec, void *payload)
|
||||
{
|
||||
UNUSED(spec);
|
||||
UNUSED(payload);
|
||||
|
||||
char *git_base_path = (char *)payload;
|
||||
if (!git_base_path)
|
||||
{
|
||||
gj_log_internal("git_base_path not in payload. Why?\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int full_path_length = strlen(git_base_path) + 1 + strlen(path);
|
||||
char *full_path = (char *)malloc(full_path_length);
|
||||
if (full_path == NULL)
|
||||
{
|
||||
gj_log_internal("rm_match_cb: Malloc Failed");
|
||||
return 1;
|
||||
}
|
||||
strcpy(full_path, git_base_path);
|
||||
strcat(full_path, "/"); // FIXME: Will not work on windows!
|
||||
strcat(full_path, path);
|
||||
|
||||
gj_log_internal("Removing File: %s\n", full_path);
|
||||
int err = remove(full_path);
|
||||
if (err != 0)
|
||||
{
|
||||
gj_log_internal("File could not be deleted: %s %d\n", full_path, errno);
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
gj_log_internal("ENOENT\n");
|
||||
}
|
||||
}
|
||||
|
||||
free(full_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gj_git_rm(const char *git_base_path, const char *pattern)
|
||||
{
|
||||
int err;
|
||||
git_repository *repo = NULL;
|
||||
git_index *index = NULL;
|
||||
|
||||
err = git_repository_open(&repo, git_base_path);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_repository_index(&index, repo);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
char *paths[] = {(char *)pattern};
|
||||
git_strarray pathspec = {paths, 1};
|
||||
|
||||
gj_log_internal("Calling git rm with pathspec %s", pattern);
|
||||
err = git_index_remove_all(index, &pathspec, rm_match_cb, (void *)git_base_path);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_index_write(index);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
git_index_free(index);
|
||||
git_repository_free(repo);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int gj_git_init(const char *git_base_path)
|
||||
{
|
||||
int err = 0;
|
||||
git_repository *repo = NULL;
|
||||
|
||||
git_repository_init_options initopts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
|
||||
initopts.flags = GIT_REPOSITORY_INIT_MKPATH;
|
||||
initopts.workdir_path = git_base_path;
|
||||
|
||||
err = git_repository_init_ext(&repo, git_base_path, &initopts);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
git_repository_free(repo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gj_git_reset_hard(const char *git_base_path, const char *ref)
|
||||
{
|
||||
int err = 0;
|
||||
git_repository *repo = NULL;
|
||||
git_object *obj = NULL;
|
||||
|
||||
err = git_repository_open(&repo, git_base_path);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_revparse_single(&obj, repo, ref);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_reset(repo, obj, GIT_RESET_HARD, NULL);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
git_object_free(obj);
|
||||
git_repository_free(repo);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int gj_git_commit(const char *git_base_path, const char *author_name,
|
||||
const char *author_email, const char *message, long long commit_time, int commit_time_offset)
|
||||
{
|
||||
int err = 0;
|
||||
git_signature *sig = NULL;
|
||||
git_index *index = NULL;
|
||||
git_oid tree_id, commit_id;
|
||||
git_tree *tree = NULL;
|
||||
git_repository *repo = NULL;
|
||||
git_oid parent_id;
|
||||
git_commit *parent_commit = NULL;
|
||||
|
||||
err = git_repository_open(&repo, git_base_path);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_repository_index(&index, repo);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
FIXME: This returns 0 when a file is set to be removed
|
||||
How do we figure out when the index is empty?
|
||||
int numOps = git_index_entrycount(index);
|
||||
if (numOps == 0)
|
||||
{
|
||||
err = GJ_ERR_EMPTY_COMMIT;
|
||||
goto cleanup;
|
||||
}
|
||||
*/
|
||||
|
||||
if (commit_time == 0)
|
||||
{
|
||||
err = git_signature_now(&sig, author_name, author_email);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = git_signature_new(&sig, author_name, author_email, commit_time, commit_time_offset);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = git_index_write_tree(&tree_id, index);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_tree_lookup(&tree, repo, &tree_id);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_reference_name_to_id(&parent_id, repo, "HEAD");
|
||||
if (err < 0)
|
||||
{
|
||||
if (err != GIT_ENOTFOUND)
|
||||
goto cleanup;
|
||||
|
||||
git_error_clear();
|
||||
|
||||
err = git_commit_create(&commit_id, repo, "HEAD", sig, sig, NULL, message, tree, 0, NULL);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = git_commit_lookup(&parent_commit, repo, &parent_id);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
const git_commit *parents = {parent_commit};
|
||||
err = git_commit_create(&commit_id, repo, "HEAD", sig, sig, NULL, message, tree, 1, &parents);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
git_index_free(index);
|
||||
git_commit_free(parent_commit);
|
||||
git_tree_free(tree);
|
||||
git_repository_free(repo);
|
||||
git_signature_free(sig);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int fetch_progress(const git_transfer_progress *stats, void *payload)
|
||||
{
|
||||
UNUSED(payload);
|
||||
|
||||
int fetch_percent =
|
||||
(100 * stats->received_objects) /
|
||||
stats->total_objects;
|
||||
int index_percent =
|
||||
(100 * stats->indexed_objects) /
|
||||
stats->total_objects;
|
||||
int kbytes = stats->received_bytes / 1024;
|
||||
|
||||
gj_log_internal("network %3d%% (%4d kb, %5d/%5d) /"
|
||||
" index %3d%% (%5d/%5d)\n",
|
||||
fetch_percent, kbytes,
|
||||
stats->received_objects, stats->total_objects,
|
||||
index_percent,
|
||||
stats->indexed_objects, stats->total_objects);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *g_public_key_path = NULL;
|
||||
char *g_private_key_path = NULL;
|
||||
char *g_passcode = NULL;
|
||||
|
||||
void gj_set_ssh_keys_paths(char *public_key, char *private_key, char *passcode)
|
||||
{
|
||||
g_public_key_path = public_key;
|
||||
g_private_key_path = private_key;
|
||||
g_passcode = passcode;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool first_time;
|
||||
int error_code;
|
||||
} gj_credentials_payload;
|
||||
|
||||
int credentials_cb(git_cred **out, const char *url, const char *username_from_url,
|
||||
unsigned int allowed_types, void *payload)
|
||||
{
|
||||
if (!payload)
|
||||
{
|
||||
gj_log_internal("credentials_cb has no payload\n");
|
||||
return -1;
|
||||
}
|
||||
gj_credentials_payload *gj_payload = (gj_credentials_payload *)payload;
|
||||
if (!gj_payload->first_time)
|
||||
{
|
||||
gj_payload->error_code = GJ_ERR_INVALID_CREDENTIALS;
|
||||
gj_log_internal("GitJournal: Credentials have been tried and they failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
gj_log_internal("Url: %s\n", url);
|
||||
|
||||
if (!(allowed_types & GIT_CREDTYPE_SSH_KEY))
|
||||
{
|
||||
gj_log_internal("Some other auth mechanism is being used: %d\n", allowed_types);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gj_payload->first_time = false;
|
||||
return git_cred_ssh_key_new(out, username_from_url,
|
||||
g_public_key_path, g_private_key_path, g_passcode);
|
||||
}
|
||||
|
||||
int certificate_check_cb(git_cert *cert, int valid, const char *host, void *payload)
|
||||
{
|
||||
gj_log_internal("Valid: %d\n", valid);
|
||||
gj_log_internal("CertType: %d\n", cert->cert_type);
|
||||
|
||||
if (valid == 0)
|
||||
{
|
||||
gj_log_internal("%s: Invalid certificate\n", host);
|
||||
}
|
||||
|
||||
if (cert->cert_type == GIT_CERT_HOSTKEY_LIBSSH2)
|
||||
{
|
||||
gj_log_internal("LibSSH2 Key: %p\n", payload);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gj_git_clone(const char *clone_url, const char *git_base_path)
|
||||
{
|
||||
int err;
|
||||
git_repository *repo = NULL;
|
||||
git_clone_options options = GIT_CLONE_OPTIONS_INIT;
|
||||
options.fetch_opts.callbacks.transfer_progress = fetch_progress;
|
||||
options.fetch_opts.callbacks.certificate_check = certificate_check_cb;
|
||||
|
||||
gj_credentials_payload gj_payload = {true, 0};
|
||||
options.fetch_opts.callbacks.payload = (void *)&gj_payload;
|
||||
options.fetch_opts.callbacks.credentials = credentials_cb;
|
||||
|
||||
err = git_clone(&repo, clone_url, git_base_path, &options);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
git_repository_free(repo);
|
||||
|
||||
if (gj_payload.error_code != 0)
|
||||
return gj_payload.error_code;
|
||||
return err;
|
||||
}
|
||||
|
||||
char *gj_branch_name(git_repository *repo)
|
||||
{
|
||||
int err = 0;
|
||||
git_reference *ref = NULL;
|
||||
char *shorthand = "master";
|
||||
|
||||
err = git_repository_head(&ref, repo);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
shorthand = (char *)git_reference_shorthand(ref);
|
||||
|
||||
cleanup:
|
||||
git_reference_free(ref);
|
||||
|
||||
return shorthand;
|
||||
}
|
||||
|
||||
int gj_git_push(const char *git_base_path)
|
||||
{
|
||||
int err = 0;
|
||||
git_repository *repo = NULL;
|
||||
git_remote *remote = NULL;
|
||||
char *name = NULL;
|
||||
|
||||
err = git_repository_open(&repo, git_base_path);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_remote_lookup(&remote, repo, "origin");
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
// Get remote name
|
||||
const char *branch_name = gj_branch_name(repo);
|
||||
char *base_name = "refs/heads/";
|
||||
|
||||
int name_length = strlen(base_name) + strlen(branch_name);
|
||||
name = (char *)malloc(name_length);
|
||||
if (name == NULL)
|
||||
{
|
||||
gj_log_internal("gj_git_push: malloc string failed. Length: %d", name_length);
|
||||
err = 5000;
|
||||
goto cleanup;
|
||||
}
|
||||
strcpy(name, base_name);
|
||||
strcat(name, branch_name);
|
||||
|
||||
const git_strarray refs = {&name, 1};
|
||||
|
||||
git_push_options options = GIT_PUSH_OPTIONS_INIT;
|
||||
|
||||
gj_credentials_payload gj_payload = {true};
|
||||
options.callbacks.payload = (void *)&gj_payload;
|
||||
options.callbacks.credentials = credentials_cb;
|
||||
|
||||
err = git_remote_push(remote, &refs, &options);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
free(name);
|
||||
git_remote_free(remote);
|
||||
git_repository_free(repo);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// Taken from merge.c libgit2 examples
|
||||
static int perform_fastforward(git_repository *repo, const git_oid *target_oid)
|
||||
{
|
||||
git_checkout_options ff_checkout_options = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
git_reference *target_ref = NULL;
|
||||
git_reference *new_target_ref = NULL;
|
||||
git_object *target = NULL;
|
||||
int err = 0;
|
||||
|
||||
err = git_repository_head(&target_ref, repo);
|
||||
if (err != 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Lookup the target object */
|
||||
err = git_object_lookup(&target, repo, target_oid, GIT_OBJECT_COMMIT);
|
||||
if (err != 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Checkout the result so the workdir is in the expected state */
|
||||
ff_checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE;
|
||||
err = git_checkout_tree(repo, target, &ff_checkout_options);
|
||||
if (err != 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Move the target reference to the target OID */
|
||||
err = git_reference_set_target(&new_target_ref, target_ref, target_oid, NULL);
|
||||
if (err != 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
git_reference_free(target_ref);
|
||||
git_reference_free(new_target_ref);
|
||||
git_object_free(target);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int gj_git_pull(const char *git_base_path, const char *author_name, const char *author_email)
|
||||
{
|
||||
int err = 0;
|
||||
git_repository *repo = NULL;
|
||||
git_remote *remote = NULL;
|
||||
git_annotated_commit *origin_annotated_commit = NULL;
|
||||
git_reference *origin_head_ref = NULL;
|
||||
git_index *index = NULL;
|
||||
git_index_conflict_iterator *conflict_iter = NULL;
|
||||
git_signature *sig = NULL;
|
||||
|
||||
git_commit *head_commit = NULL;
|
||||
git_commit *origin_head_commit = NULL;
|
||||
git_tree *tree = NULL;
|
||||
git_oid tree_id;
|
||||
char *name = NULL;
|
||||
|
||||
err = git_repository_open(&repo, git_base_path);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
git_repository_state_t state = git_repository_state(repo);
|
||||
if (state != GIT_REPOSITORY_STATE_NONE)
|
||||
{
|
||||
err = GJ_ERR_PULL_INVALID_STATE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = git_remote_lookup(&remote, repo, "origin");
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
git_fetch_options options = GIT_FETCH_OPTIONS_INIT;
|
||||
|
||||
gj_credentials_payload gj_payload = {true};
|
||||
options.callbacks.payload = (void *)&gj_payload;
|
||||
options.callbacks.credentials = credentials_cb;
|
||||
|
||||
err = git_remote_fetch(remote, NULL, &options, NULL);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
// Get remote name
|
||||
const char *branch_name = gj_branch_name(repo);
|
||||
char *base_name = "refs/remotes/origin/";
|
||||
|
||||
int name_length = strlen(base_name) + strlen(branch_name);
|
||||
name = (char *)malloc(name_length);
|
||||
if (name == NULL)
|
||||
{
|
||||
gj_log_internal("gj_git_pull: malloc string failed. Length: %d", name_length);
|
||||
err = 5000;
|
||||
goto cleanup;
|
||||
}
|
||||
strcpy(name, base_name);
|
||||
strcat(name, branch_name);
|
||||
|
||||
err = git_reference_lookup(&origin_head_ref, repo, name);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_annotated_commit_from_ref(&origin_annotated_commit, repo, origin_head_ref);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
git_merge_analysis_t merge_analysis;
|
||||
git_merge_preference_t merge_preference;
|
||||
|
||||
git_annotated_commit *annotated_commits[] = {origin_annotated_commit};
|
||||
err = git_merge_analysis(&merge_analysis, &merge_preference, repo,
|
||||
(const git_annotated_commit **)annotated_commits, 1);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (merge_analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
else if (merge_analysis & GIT_MERGE_ANALYSIS_UNBORN)
|
||||
{
|
||||
err = 5000;
|
||||
gj_log("GitPull merge_analysis unborn\n");
|
||||
goto cleanup;
|
||||
}
|
||||
else if (merge_analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)
|
||||
{
|
||||
gj_log("GitPull: Performing FastForward\n");
|
||||
|
||||
err = perform_fastforward(repo, git_annotated_commit_id(origin_annotated_commit));
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
else if (merge_analysis & GIT_MERGE_ANALYSIS_NORMAL)
|
||||
{
|
||||
gj_log("GitPull: Performing Normal Merge\n");
|
||||
|
||||
git_merge_options merge_options = GIT_MERGE_OPTIONS_INIT;
|
||||
git_checkout_options checkout_options = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
|
||||
err = git_merge(repo, (const git_annotated_commit **)annotated_commits, 1,
|
||||
&merge_options, &checkout_options);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_repository_index(&index, repo);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_index_conflict_iterator_new(&conflict_iter, index);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
// Handle Conflicts
|
||||
while (1)
|
||||
{
|
||||
git_index_entry *ancestor_out;
|
||||
git_index_entry *our_out;
|
||||
git_index_entry *their_out;
|
||||
err = git_index_conflict_next((const git_index_entry **)&ancestor_out,
|
||||
(const git_index_entry **)&our_out,
|
||||
(const git_index_entry **)&their_out,
|
||||
conflict_iter);
|
||||
|
||||
if (err == GIT_ITEROVER)
|
||||
{
|
||||
gj_log_internal(" Done with Conflicts\n");
|
||||
break;
|
||||
}
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
gj_log_internal("GitPull: Conflict on file %s\n", their_out->path);
|
||||
|
||||
// 1. We resolve the conflict by choosing their changes
|
||||
// TODO:
|
||||
|
||||
// 2. We remove it from the list of conflicts
|
||||
err = git_index_conflict_remove(index, their_out->path);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
// 3. We add it to the index
|
||||
err = git_index_add_bypath(index, their_out->path);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_index_write(index);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = git_index_write_tree(&tree_id, index);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_tree_lookup(&tree, repo, &tree_id);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
//
|
||||
// Make the commit
|
||||
//
|
||||
err = git_signature_now(&sig, author_name, author_email);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
// Get the parents
|
||||
git_oid head_id;
|
||||
err = git_reference_name_to_id(&head_id, repo, "HEAD");
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_commit_lookup(&head_commit, repo, &head_id);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
err = git_commit_lookup(&origin_head_commit, repo,
|
||||
git_annotated_commit_id(origin_annotated_commit));
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
const git_commit *parents[] = {head_commit, origin_head_commit};
|
||||
char *message = "Custom Merge commit";
|
||||
git_oid commit_id;
|
||||
|
||||
err = git_commit_create(&commit_id, repo, "HEAD", sig, sig, NULL, message, tree, 2, parents);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
git_tree_free(tree);
|
||||
git_commit_free(head_commit);
|
||||
git_commit_free(origin_head_commit);
|
||||
git_signature_free(sig);
|
||||
if (repo != 0)
|
||||
git_repository_state_cleanup(repo);
|
||||
git_index_conflict_iterator_free(conflict_iter);
|
||||
git_index_free(index);
|
||||
git_reference_free(origin_head_ref);
|
||||
git_annotated_commit_free(origin_annotated_commit);
|
||||
git_remote_free(remote);
|
||||
git_repository_free(repo);
|
||||
free(name);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int gj_init()
|
||||
{
|
||||
return git_libgit2_init();
|
||||
}
|
||||
|
||||
int gj_shutdown()
|
||||
{
|
||||
return git_libgit2_shutdown();
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
#ifndef _GITJOURNAL_H_
|
||||
#define _GITJOURNAL_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
int gj_init();
|
||||
int gj_shutdown();
|
||||
|
||||
int gj_git_init(const char *git_base_path);
|
||||
int gj_git_clone(const char *clone_url, const char *git_base_path);
|
||||
|
||||
int gj_git_pull(const char *git_base_path, const char *author_name, const char *author_email);
|
||||
int gj_git_push(const char *git_base_path);
|
||||
|
||||
// commit_time_offset is in minutes
|
||||
int gj_git_commit(const char *git_base_path, const char *author_name,
|
||||
const char *author_email, const char *message, long long commit_time, int commit_time_offset);
|
||||
int gj_git_reset_hard(const char *git_base_path, const char *ref);
|
||||
int gj_git_add(const char *git_base_path, const char *pattern);
|
||||
int gj_git_rm(const char *git_base_path, const char *pattern);
|
||||
|
||||
void gj_set_ssh_keys_paths(char *public_key, char *private_key, char *passcode);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *message;
|
||||
bool message_allocated;
|
||||
int code;
|
||||
} gj_error;
|
||||
|
||||
gj_error *gj_error_info(int err);
|
||||
void gj_error_free(const gj_error *err);
|
||||
|
||||
// This must be implemented by you
|
||||
void gj_log(const char *message);
|
||||
|
||||
void gj_log_internal(const char *format, ...);
|
||||
|
||||
int gj_generate_ssh_keys(const char *private_key_path,
|
||||
const char *public_key_path, const char *comment);
|
||||
|
||||
#define GJ_ERR_FIRST -954
|
||||
#define GJ_ERR_EMPTY_COMMIT -954
|
||||
#define GJ_ERR_PULL_INVALID_STATE -955
|
||||
#define GJ_ERR_OPENSSL -956
|
||||
#define GJ_ERR_INVALID_CREDENTIALS -957
|
||||
#define GJ_ERR_LAST -957
|
||||
|
||||
#endif
|
@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eux
|
||||
|
||||
export VERSION=0.17.0
|
||||
curl -sSL "https://github.com/facebook/infer/releases/download/v$VERSION/infer-linux64-v$VERSION.tar.xz" |
|
||||
sudo tar -C /opt -xJ &&
|
||||
ln -s "/opt/infer-linux64-v$VERSION/bin/infer" /usr/local/bin/infer
|
@ -1,171 +0,0 @@
|
||||
#include "gitjournal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
static unsigned char pSshHeader[11] = {0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61};
|
||||
|
||||
static int SshEncodeBuffer(unsigned char *pEncoding, int bufferLen, unsigned char *pBuffer)
|
||||
{
|
||||
int adjustedLen = bufferLen, index;
|
||||
if (*pBuffer & 0x80)
|
||||
{
|
||||
adjustedLen++;
|
||||
pEncoding[4] = 0;
|
||||
index = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 4;
|
||||
}
|
||||
pEncoding[0] = (unsigned char)(adjustedLen >> 24);
|
||||
pEncoding[1] = (unsigned char)(adjustedLen >> 16);
|
||||
pEncoding[2] = (unsigned char)(adjustedLen >> 8);
|
||||
pEncoding[3] = (unsigned char)(adjustedLen);
|
||||
memcpy(&pEncoding[index], pBuffer, bufferLen);
|
||||
return index + bufferLen;
|
||||
}
|
||||
|
||||
int write_rsa_public_key(RSA *pRsa, const char *file_path, const char *comment)
|
||||
{
|
||||
int ret = 0;
|
||||
int encodingLength = 0;
|
||||
int index = 0;
|
||||
unsigned char *nBytes = NULL, *eBytes = NULL;
|
||||
unsigned char *pEncoding = NULL;
|
||||
FILE *pFile = NULL;
|
||||
BIO *bio, *b64;
|
||||
|
||||
ERR_load_crypto_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
const BIGNUM *pRsa_mod = NULL;
|
||||
const BIGNUM *pRsa_exp = NULL;
|
||||
|
||||
RSA_get0_key(pRsa, &pRsa_mod, &pRsa_exp, NULL);
|
||||
|
||||
// reading the modulus
|
||||
int nLen = BN_num_bytes(pRsa_mod);
|
||||
nBytes = (unsigned char *)malloc(nLen);
|
||||
ret = BN_bn2bin(pRsa_mod, nBytes);
|
||||
if (ret <= 0)
|
||||
goto cleanup;
|
||||
|
||||
// reading the public exponent
|
||||
int eLen = BN_num_bytes(pRsa_exp);
|
||||
eBytes = (unsigned char *)malloc(eLen);
|
||||
if (eBytes == NULL)
|
||||
{
|
||||
gj_log_internal("write_rsa_public_key malloc failed. Length: %d", eLen);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
ret = BN_bn2bin(pRsa_exp, eBytes);
|
||||
if (ret <= 0)
|
||||
goto cleanup;
|
||||
|
||||
encodingLength = 11 + 4 + eLen + 4 + nLen;
|
||||
// correct depending on the MSB of e and N
|
||||
if (eBytes[0] & 0x80)
|
||||
encodingLength++;
|
||||
if (nBytes[0] & 0x80)
|
||||
encodingLength++;
|
||||
|
||||
pEncoding = (unsigned char *)malloc(encodingLength);
|
||||
memset(pEncoding, 0, encodingLength);
|
||||
memcpy(pEncoding, pSshHeader, 11);
|
||||
|
||||
index = SshEncodeBuffer(&pEncoding[11], eLen, eBytes);
|
||||
SshEncodeBuffer(&pEncoding[11 + index], nLen, nBytes);
|
||||
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
pFile = fopen(file_path, "w");
|
||||
bio = BIO_new_fp(pFile, BIO_CLOSE);
|
||||
BIO_printf(bio, "ssh-rsa ");
|
||||
bio = BIO_push(b64, bio);
|
||||
BIO_write(bio, pEncoding, encodingLength);
|
||||
BIO_flush(bio);
|
||||
bio = BIO_pop(b64);
|
||||
BIO_printf(bio, " %s\n", comment);
|
||||
BIO_flush(bio);
|
||||
BIO_free_all(bio);
|
||||
BIO_free(b64);
|
||||
|
||||
cleanup:
|
||||
if (pFile)
|
||||
fclose(pFile);
|
||||
|
||||
free(nBytes);
|
||||
free(eBytes);
|
||||
free(pEncoding);
|
||||
|
||||
EVP_cleanup();
|
||||
ERR_free_strings();
|
||||
|
||||
return ret > 0 ? 1 : ret;
|
||||
}
|
||||
|
||||
int gj_generate_ssh_keys(const char *private_key_path,
|
||||
const char *public_key_path, const char *comment)
|
||||
{
|
||||
int ret = 0;
|
||||
RSA *rsa = NULL;
|
||||
|
||||
BIGNUM *bne = NULL;
|
||||
BIO *bp_private = NULL;
|
||||
|
||||
int bits = 1024 * 4;
|
||||
unsigned long e = RSA_F4;
|
||||
|
||||
// Generate rsa key
|
||||
bne = BN_new();
|
||||
ret = BN_set_word(bne, e);
|
||||
if (ret != 1)
|
||||
goto cleanup;
|
||||
|
||||
rsa = RSA_new();
|
||||
ret = RSA_generate_key_ex(rsa, bits, bne, NULL);
|
||||
if (ret != 1)
|
||||
{
|
||||
gj_log_internal("Failed to generate RSA key of %d bits\n", bits);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Save private key
|
||||
bp_private = BIO_new_file(private_key_path, "w+");
|
||||
ret = PEM_write_bio_RSAPrivateKey(bp_private, rsa, NULL, NULL, 0, NULL, NULL);
|
||||
if (ret != 1)
|
||||
{
|
||||
gj_log_internal("Failed to write private key to %s\n", private_key_path);
|
||||
goto cleanup;
|
||||
}
|
||||
chmod(private_key_path, 0600);
|
||||
|
||||
// Save public key
|
||||
ret = write_rsa_public_key(rsa, public_key_path, comment);
|
||||
if (ret != 1)
|
||||
{
|
||||
gj_log_internal("Failed to write public key to %s\n", public_key_path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
BIO_free_all(bp_private);
|
||||
RSA_free(rsa);
|
||||
BN_free(bne);
|
||||
|
||||
if (ret != 1)
|
||||
return GJ_ERR_OPENSSL;
|
||||
return 0;
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
#include "gitjournal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int handle_error(int err)
|
||||
{
|
||||
if (err != 0)
|
||||
{
|
||||
const gj_error *e = gj_error_info(err);
|
||||
if (e)
|
||||
{
|
||||
printf("Error %d/%d: %s\n", err, e->code, e->message);
|
||||
gj_error_free(e);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void gj_log(const char *message)
|
||||
{
|
||||
printf("%s", message);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
gj_init();
|
||||
|
||||
char *publickey = "./.ssh/id_rsa.pub";
|
||||
char *privatekey = "./.ssh/id_rsa";
|
||||
char *passphrase = "";
|
||||
|
||||
gj_set_ssh_keys_paths(publickey, privatekey, passphrase);
|
||||
|
||||
int err;
|
||||
char *git_base_path = "/tmp/test";
|
||||
//char *clone_url = "https://github.com/GitJournal/journal_test.git";
|
||||
//char *clone_url = "git@github.com:GitJournal/journal_test.git";
|
||||
char *clone_url = "git@github.com:vhanda/test_gj.git";
|
||||
//char *clone_url = "root@pi.local:git/test";
|
||||
char *add_pattern = ".";
|
||||
char *author_name = "TestMan";
|
||||
char *author_email = "TestMan@example.com";
|
||||
char *message = "Commit message for GitJournal";
|
||||
|
||||
err = gj_generate_ssh_keys("/tmp/t/id_rsa", "/tmp/t/id_rsa.pub", "Cookie");
|
||||
//err = gj_git_init(git_base_path);
|
||||
//err = gj_git_commit(git_base_path, author_name, author_email, message);
|
||||
//err = gj_git_clone(clone_url, git_base_path);
|
||||
//err = gj_git_push(git_base_path);
|
||||
//err = gj_git_pull(git_base_path, author_name, author_email);
|
||||
//err = gj_git_add(git_base_path, "9.md");
|
||||
//err = gj_git_rm(git_base_path, "9.md");
|
||||
//err = gj_git_reset_hard(git_base_path, "HEAD^");
|
||||
|
||||
if (err < 0)
|
||||
handle_error(err);
|
||||
printf("We seem to be done\n");
|
||||
|
||||
gj_shutdown();
|
||||
|
||||
/*
|
||||
int features = git_libgit2_features();
|
||||
bool supports_threading = features & GIT_FEATURE_THREADS;
|
||||
bool supports_https2 = features & GIT_FEATURE_HTTPS;
|
||||
bool supports_ssh = features & GIT_FEATURE_SSH;
|
||||
printf("Threading: %d\n", supports_threading);
|
||||
printf("Https: %d\n", supports_https2);
|
||||
printf("SSH: %d\n", supports_ssh);
|
||||
*/
|
||||
return 0;
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fimber/fimber.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:flutter_crashlytics/flutter_crashlytics.dart';
|
||||
@ -56,176 +54,3 @@ Future<Directory> getGitBaseDirectory() async {
|
||||
}
|
||||
return Directory(path);
|
||||
}
|
||||
|
||||
class GitRepo {
|
||||
final String folderPath;
|
||||
final String authorName;
|
||||
final String authorEmail;
|
||||
|
||||
const GitRepo({
|
||||
@required this.folderPath,
|
||||
@required this.authorName,
|
||||
@required this.authorEmail,
|
||||
});
|
||||
|
||||
static Future<void> clone(String folderPath, String cloneUrl) async {
|
||||
try {
|
||||
await invokePlatformMethod('gitClone', {
|
||||
'cloneUrl': cloneUrl,
|
||||
'folderPath': folderPath,
|
||||
});
|
||||
Fimber.d("Done");
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("gitClone Failed: '${e.message}'.");
|
||||
throw createGitException(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> init(String folderPath) async {
|
||||
try {
|
||||
await invokePlatformMethod('gitInit', {
|
||||
'folderPath': folderPath,
|
||||
});
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("gitInit Failed: '${e.message}'.");
|
||||
throw createGitException(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> pull() async {
|
||||
try {
|
||||
await invokePlatformMethod('gitPull', {
|
||||
'folderPath': folderPath,
|
||||
'authorName': authorName,
|
||||
'authorEmail': authorEmail,
|
||||
});
|
||||
Fimber.d("Done");
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("gitPull Failed: '${e.message}'.");
|
||||
throw createGitException(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> add(String filePattern) async {
|
||||
try {
|
||||
await invokePlatformMethod('gitAdd', {
|
||||
'folderPath': folderPath,
|
||||
'filePattern': filePattern,
|
||||
});
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("gitAdd Failed: '${e.message}'.");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> rm(String filePattern) async {
|
||||
try {
|
||||
await invokePlatformMethod('gitRm', {
|
||||
'folderPath': folderPath,
|
||||
'filePattern': filePattern,
|
||||
});
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("gitRm Failed: '${e.message}'.");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> push() async {
|
||||
try {
|
||||
await invokePlatformMethod('gitPush', {
|
||||
'folderPath': folderPath,
|
||||
});
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("gitPush Failed: '${e.message}'.");
|
||||
throw createGitException(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Change this method to just resetHard
|
||||
Future<void> resetLast() async {
|
||||
try {
|
||||
await invokePlatformMethod('gitResetLast', {
|
||||
'folderPath': folderPath,
|
||||
});
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("gitResetLast Failed: '${e.message}'.");
|
||||
throw createGitException(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Change the datetime
|
||||
// FIXME: Actually implement the 'when'
|
||||
Future<void> commit({@required String message, String when}) async {
|
||||
try {
|
||||
await invokePlatformMethod('gitCommit', {
|
||||
'folderPath': folderPath,
|
||||
'authorName': authorName,
|
||||
'authorEmail': authorEmail,
|
||||
'message': message,
|
||||
'when': when,
|
||||
});
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("gitCommit Failed: '${e.message}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> generateSSHKeys({@required String comment}) async {
|
||||
Fimber.d("generateSSHKeyss: " + comment);
|
||||
try {
|
||||
String publicKey = await invokePlatformMethod('generateSSHKeys', {
|
||||
'comment': comment,
|
||||
});
|
||||
Fimber.d("Public Key " + publicKey);
|
||||
return publicKey;
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("Failed to generateSSHKeys: '${e.message}'.");
|
||||
}
|
||||
|
||||
try {
|
||||
String publicKey = await invokePlatformMethod('getSSHPublicKey');
|
||||
Fimber.d("Public Key " + publicKey);
|
||||
return publicKey;
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("Failed to getSSHPublicKey: '${e.message}'.");
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
Future<void> setSshKeys({
|
||||
@required String publicKey,
|
||||
@required String privateKey,
|
||||
}) async {
|
||||
Fimber.d("setSshKeys");
|
||||
try {
|
||||
await invokePlatformMethod('setSshKeys', {
|
||||
'publicKey': publicKey,
|
||||
'privateKey': privateKey,
|
||||
});
|
||||
} on PlatformException catch (e) {
|
||||
Fimber.d("Failed to setSSHKeys: '${e.message}'.");
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
class GitException implements Exception {
|
||||
final String cause;
|
||||
GitException(this.cause);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "GitException: " + cause;
|
||||
}
|
||||
}
|
||||
|
||||
GitException createGitException(String msg) {
|
||||
if (msg.contains("ENETUNREACH")) {
|
||||
return GitException("No Connection");
|
||||
}
|
||||
if (msg.contains("Remote origin did not advertise Ref for branch master")) {
|
||||
return GitException("No master branch");
|
||||
}
|
||||
if (msg.contains("Nothing to push")) {
|
||||
return GitException("Nothing to push.");
|
||||
}
|
||||
return GitException(msg);
|
||||
}
|
||||
|
@ -3,7 +3,8 @@ import 'dart:io';
|
||||
|
||||
import 'package:fimber/fimber.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:gitjournal/apis/git.dart';
|
||||
import 'package:git_bindings/git.dart';
|
||||
|
||||
import 'package:gitjournal/settings.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
|
@ -8,6 +8,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import 'package:git_bindings/git.dart';
|
||||
|
||||
import 'package:gitjournal/apis/git.dart';
|
||||
import 'package:gitjournal/settings.dart';
|
||||
import 'package:gitjournal/state_container.dart';
|
||||
|
@ -3,7 +3,8 @@ import 'dart:io';
|
||||
|
||||
import 'package:fimber/fimber.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:gitjournal/apis/git.dart';
|
||||
import 'package:git_bindings/git.dart';
|
||||
|
||||
import 'package:gitjournal/core/note.dart';
|
||||
import 'package:gitjournal/core/notes_folder.dart';
|
||||
import 'package:gitjournal/settings.dart';
|
||||
|
128
lib/gitapp.dart
128
lib/gitapp.dart
@ -1,128 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gitjournal/apis/git.dart';
|
||||
import 'package:gitjournal/apis/git_migration.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
const gitFolderName = "journal";
|
||||
String cloneUrl = "git@github.com:GitJournal/journal_test.git";
|
||||
|
||||
class GitApp extends StatefulWidget {
|
||||
@override
|
||||
_GitAppState createState() => _GitAppState();
|
||||
}
|
||||
|
||||
class _GitAppState extends State<GitApp> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
GitRepo gitRepo;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
getGitBaseDirectory().then((dir) async {
|
||||
var repoPath = p.join(dir.path, gitFolderName);
|
||||
gitRepo = GitRepo(
|
||||
folderPath: repoPath,
|
||||
authorName: "Vishesh Handa",
|
||||
authorEmail: "noemail@example.com",
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Git App',
|
||||
home: Scaffold(
|
||||
key: _scaffoldKey,
|
||||
appBar: AppBar(
|
||||
title: const Text('Git Test'),
|
||||
),
|
||||
body: Column(
|
||||
children: _buildGitButtons(),
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _sendSuccess() {
|
||||
var text = "Success";
|
||||
_scaffoldKey.currentState
|
||||
..removeCurrentSnackBar()
|
||||
..showSnackBar(SnackBar(content: Text(text)));
|
||||
}
|
||||
|
||||
void _sendError(String text) {
|
||||
_scaffoldKey.currentState
|
||||
..removeCurrentSnackBar()
|
||||
..showSnackBar(SnackBar(content: Text("ERROR: " + text)));
|
||||
}
|
||||
|
||||
List<Widget> _buildGitButtons() {
|
||||
return <Widget>[
|
||||
RaisedButton(
|
||||
child: const Text("Generate Keys"),
|
||||
onPressed: () {
|
||||
generateSSHKeys(comment: "Git Sample App");
|
||||
}),
|
||||
RaisedButton(
|
||||
child: const Text("Git Clone"),
|
||||
onPressed: () async {
|
||||
try {
|
||||
await GitRepo.clone(gitRepo.folderPath, cloneUrl);
|
||||
_sendSuccess();
|
||||
} on GitException catch (ex) {
|
||||
print(ex);
|
||||
_sendError(ex.toString());
|
||||
}
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
child: const Text("Git Pull"),
|
||||
onPressed: () async {
|
||||
gitRepo.pull();
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
child: const Text("Git Add"),
|
||||
onPressed: () async {
|
||||
gitRepo.add(".");
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
child: const Text("Git Push"),
|
||||
onPressed: () async {
|
||||
gitRepo.push();
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
child: const Text("Git Commit"),
|
||||
onPressed: () async {
|
||||
gitRepo.commit(
|
||||
message: "Default message from GitJournal",
|
||||
when: "2017-10-20T01:21:10+02:00",
|
||||
);
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
child: const Text("Git Reset Last"),
|
||||
onPressed: () async {
|
||||
gitRepo.resetLast();
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
child: const Text("Git Migrate"),
|
||||
onPressed: () async {
|
||||
var baseGitPath = await getGitBaseDirectory();
|
||||
await migrateGitRepo(
|
||||
fromGitBasePath: "journal_local",
|
||||
toGitBaseFolder: "journal",
|
||||
gitBasePath: baseGitPath.path,
|
||||
);
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
@ -3,8 +3,9 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:function_types/function_types.dart';
|
||||
|
||||
import 'package:git_bindings/git.dart';
|
||||
|
||||
import 'package:gitjournal/analytics.dart';
|
||||
import 'package:gitjournal/apis/git.dart';
|
||||
import 'package:gitjournal/apis/githost_factory.dart';
|
||||
import 'package:gitjournal/settings.dart';
|
||||
|
||||
|
@ -4,9 +4,11 @@ import 'package:dots_indicator/dots_indicator.dart';
|
||||
import 'package:fimber/fimber.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:function_types/function_types.dart';
|
||||
import 'package:git_bindings/git.dart';
|
||||
|
||||
import 'package:gitjournal/analytics.dart';
|
||||
import 'package:gitjournal/apis/git.dart';
|
||||
import 'package:gitjournal/apis/githost_factory.dart';
|
||||
import 'package:gitjournal/state_container.dart';
|
||||
import 'package:gitjournal/utils.dart';
|
||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:gitjournal/core/note.dart';
|
||||
import 'package:gitjournal/core/notes_folder.dart';
|
||||
import 'package:gitjournal/utils.dart';
|
||||
import 'package:gitjournal/apis/git.dart';
|
||||
import 'package:git_bindings/git.dart';
|
||||
import 'package:gitjournal/screens/journal_editor.dart';
|
||||
import 'package:gitjournal/screens/journal_browsing.dart';
|
||||
import 'package:gitjournal/state_container.dart';
|
||||
|
@ -210,6 +210,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
git_bindings:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: git_bindings
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -30,6 +30,7 @@ dependencies:
|
||||
flutter_staggered_grid_view: ^0.3.0
|
||||
page_transition: "^1.1.5"
|
||||
provider: ^3.2.0
|
||||
git_bindings: 0.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_launcher_icons: "^0.7.2"
|
||||
|
@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eux
|
||||
|
||||
cd "$(dirname "$0")"/../android/app
|
||||
|
||||
BUILD_NUM=$(curl -s 'https://circleci.com/api/v1.1/project/github/GitJournal/ndk-libraries?limit=1&offset=0&filter=successful' | jq .[0] | jq -r .build_num)
|
||||
echo "CircleCI Buld Number: $BUILD_NUM"
|
||||
|
||||
URL=$(curl -s https://circleci.com/api/v1.1/project/github/GitJournal/ndk-libraries/$BUILD_NUM/artifacts | grep -o 'https://[^"]*libs.tar')
|
||||
|
||||
echo "Downloading $URL"
|
||||
|
||||
curl "$URL" -o "libs.tar"
|
||||
rm -rf libs
|
||||
tar xf libs.tar
|
||||
mv libs ci_libs
|
||||
mkdir libs
|
||||
cp -r ci_libs/openssl-lib/* libs/
|
||||
cp -r ci_libs/libssh2/* libs/
|
||||
cp -r ci_libs/libgit2/* libs/
|
||||
rm -rf ci_libs
|
||||
rm libs.tar
|
@ -1,45 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
import 'package:gitjournal/apis/git.dart';
|
||||
import 'package:gitjournal/gitapp.dart';
|
||||
|
||||
void main() async {
|
||||
// This line enables the extension
|
||||
enableFlutterDriverExtension();
|
||||
|
||||
await setSshKeys(
|
||||
privateKey: """
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAyPlNUPGo2vCK/w4jN90yxhvrAvSmaAohhYmyzT3NLpw97eW9
|
||||
Td2JSQE+D3Mcb0QK10aFdz1Q11IAF1bP7F9FMMvwpwT3283u+m8wNfRqELtWkbFW
|
||||
8F011hzklrQe14AhBrj+pL64lL5GQBv8IrHMiYtvDI3QDbBfjm+G+TMYaYgcSt1q
|
||||
jmyz5NgW7kFjG8Q83/GWliSryGGnkSYE3vudKHutdJ68w+1Fi2c7wqOxGSLQEu4Y
|
||||
VD0nUYpx9f8r0wXHNvydcE2+b1jlBlVXvRgUu2RXyuVULOq6oU3DmQsn/0ry1eq/
|
||||
A3FkBPuewu1kLrTLrJ2bxyhaDLCIDwkfilhgnwIDAQABAoIBAFRXzArcYHEB4lOI
|
||||
K1+WhWh+7vIemnevSMIyN8fK2AFnsNXWRMwY3TS2QMVbGePYOnR+NCUGppa24zLo
|
||||
S/p3QSJpdGWjwCGPG2wena0HFjxPYtViB4p4k8938LcOgKMQMswPd07Me8pw0Cq3
|
||||
k+k7lQtkaQZrvZUBIBk21P5gYy5mIgSDuVRMe4ogzC4LsHShhCj9bffi7TjQb4lc
|
||||
/NDjTqP94uB+o6lFeTTRgM+1mZYV2zy3x77ewgSrzfPHEB+7AFItXF1NdjaMJFSD
|
||||
D7bwldH548Di/qW0UMJDSV83Zwcek9jhPl9d9cQR5UwMKRJfbFNg2i1SxFQjqYBB
|
||||
v4ucywECgYEA9RUPZ6WJaluDC0ozji46WGvl5P2soEdXKEOSXkximgMVZKkDLraG
|
||||
aUi+QMT6IvSiNNGtBx6od0iYELc5V004FvRqV0jYLVFLkfJtiZWmhSFqkwPSdBIL
|
||||
NFE3/KjnMiSnQJ8oeORAYp8Qj52S3j09ruXkLxkRonr7rO3MMXXKn5cCgYEA0e05
|
||||
tA3qb+Wy9SoDH4klSXmKgxT1/Ka9kyro7S6rL3UbKa9yacpNEtHTOO6PtHTHCPze
|
||||
vGjmJAPBNemKq82hTwoAfcCcQRuluKNAE+f/0DXmzVCd012QPK7pcD24+ZdGEecJ
|
||||
injgsBEb98i1ne8A4QggzObbbhXgXRqUpeB26DkCgYEAyBVpfjSm+y26znzFmk4j
|
||||
VAzCozB2vmN/xF9mH5Y86X+a95MEBh79nPbGXBp0HBWcV4LWv/lHkBq0CvGK3rss
|
||||
D5F7P8c4tcao633/71M9n3Koj12PczNH8m5cRumd1lIWOau2Xvv5lIpH+vep78YP
|
||||
lboZkFnnC79buNJq4fZIdgECgYB39yVerAUpZQ7b4+JdBzbzwi1Rs4zPkUoM7Byo
|
||||
Tl8tg7K+I7Eym5VoB9i5VDtzWLjVfgybhybdtfeYI5pHi/9+96xIMOYanv4ZgdGA
|
||||
jrg1+FepRUSsIW/n/d0Rc3RdzgERAgMFywY8F8rv0xdW5dqOvuJfth33zzCkhCgm
|
||||
kxvgoQKBgQCtpv31vAhpW5Hsz6i+ltID8ePQ5f9zVs9LcsNhr4yH28kT+ahVQDov
|
||||
ef8YxSqfUYF66rqYp9OKt/Gm6R6aysE6XZaLdsonFc+jxX7ww+PDnZ+2ysNqbQYg
|
||||
IzaFDjJprJTo6g679GYSWXmq0Mj1wesuh7Ccz+u3bsVLm3hpp/nMDg==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
""",
|
||||
publicKey:
|
||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDI+U1Q8aja8Ir/DiM33TLGG+sC9KZoCiGFibLNPc0unD3t5b1N3YlJAT4PcxxvRArXRoV3PVDXUgAXVs/sX0Uwy/CnBPfbze76bzA19GoQu1aRsVbwXTXWHOSWtB7XgCEGuP6kvriUvkZAG/wiscyJi28MjdANsF+Ob4b5MxhpiBxK3WqObLPk2BbuQWMbxDzf8ZaWJKvIYaeRJgTe+50oe610nrzD7UWLZzvCo7EZItAS7hhUPSdRinH1/yvTBcc2/J1wTb5vWOUGVVe9GBS7ZFfK5VQs6rqhTcOZCyf/SvLV6r8DcWQE+57C7WQutMusnZvHKFoMsIgPCR+KWGCf gitjournal git testing",
|
||||
);
|
||||
|
||||
runApp(GitApp());
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
import 'package:flutter_driver/flutter_driver.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('Git Test', () {
|
||||
// First, define the Finders. We can use these to locate Widgets from the
|
||||
// test suite. Note: the Strings provided to the `byValueKey` method must
|
||||
// be the same as the Strings we used for the Keys in step 1.
|
||||
// final counterTextFinder = find.byValueKey('counter');
|
||||
final buttonFinder = find.text('Git Clone');
|
||||
|
||||
FlutterDriver driver;
|
||||
|
||||
// Connect to the Flutter driver before running any tests
|
||||
setUpAll(() async {
|
||||
driver = await FlutterDriver.connect();
|
||||
});
|
||||
|
||||
// Close the connection to the driver after the tests have completed
|
||||
tearDownAll(() async {
|
||||
if (driver != null) {
|
||||
driver.close();
|
||||
}
|
||||
});
|
||||
|
||||
test('Anonymous GitClone works', () async {
|
||||
await driver.waitFor(buttonFinder);
|
||||
await driver.tap(buttonFinder);
|
||||
await driver.waitFor(
|
||||
find.text("Success"),
|
||||
timeout: const Duration(seconds: 15),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user