فهرست منبع

[add] git fetch blob and trees

isundil 7 سال پیش
والد
کامیت
d96b29674b

+ 1 - 1
app/src/main/AndroidManifest.xml

@@ -39,6 +39,6 @@
         <activity
             android:name=".ui.EditPasswordActivity"
             android:windowSoftInputMode="adjustResize" />
-        <activity android:name=".git.ui.GitPullActivity"/>
+        <activity android:name=".ui.GitPullActivity"/>
     </application>
 </manifest>

+ 88 - 55
app/src/main/java/info/knacki/pass/git/DumbGitInterface.java

@@ -1,23 +1,18 @@
 package info.knacki.pass.git;
 
-import android.arch.core.util.Function;
 import android.os.AsyncTask;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
 import java.net.Authenticator;
 import java.net.MalformedURLException;
 import java.net.PasswordAuthentication;
 import java.net.URL;
 import java.net.URLConnection;
 import java.nio.charset.Charset;
-import java.security.InvalidKeyException;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.InvalidPropertiesFormatException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.zip.InflaterInputStream;
@@ -25,7 +20,6 @@ import java.util.zip.InflaterInputStream;
 import info.knacki.pass.git.entities.GitCommit;
 import info.knacki.pass.git.entities.GitObject;
 import info.knacki.pass.git.entities.GitRef;
-import info.knacki.pass.git.entities.Util;
 import info.knacki.pass.settings.SettingsManager;
 
 class DumbGitInterface implements GitInterface {
@@ -73,7 +67,16 @@ class DumbGitInterface implements GitInterface {
                         }
                         ++i;
                     }
-                    callback.onResponse(buffer);
+
+                    for (i =0; i < totalRead && buffer[i] != 0; ++i);
+                    if (i != totalRead) {
+                        ++i;
+                        byte []arr = new byte[buffer.length -i];
+                        System.arraycopy(buffer, i, arr, 0, totalRead -i);
+                        callback.onResponse(arr);
+                    } else {
+                        callback.onResponse(buffer);
+                    }
                 }
                 catch (MalformedURLException e) {
                     log.log(Level.WARNING, e.getMessage(), e);
@@ -178,52 +181,86 @@ class DumbGitInterface implements GitInterface {
         });
     }
 
-    // FIXME recursive strategy
-
-    public void RecursiveFetchTree(final GitObject.GitTree rootTree, final OnResponseListener<GitObject.GitTree> response) {
-        response.onResponse(rootTree);
-    }
+    public void FetchTree(final GitCommit ci, final OnStreamResponseListener<GitObject.GitTree> response) {
+        class RecursiveFetchTreeWalker implements OnResponseListener<byte[]> {
+            private final GitObject.GitTree fRoot;
+            private GitObject.GitTree fCurrentTree;
+            private final OnStreamResponseListener<GitObject.GitTree> fResponseListener;
 
-    private void FillTree(final GitObject.GitTree tree, byte[] data) {
-        int i = 3;
+            private RecursiveFetchTreeWalker(GitCommit ci, final OnStreamResponseListener<GitObject.GitTree> responseListener) {
+                fRoot = fCurrentTree = new GitObject.GitTree(ci.GetTree()).Initialize();
+                fResponseListener = responseListener;
+            }
 
-        while (data[i -1] != 0 && i < data.length)
-            ++i;
-        while (i < data.length) {
-            byte[] mode = new byte[6];
-            System.arraycopy(data, i, mode, 0, 6);
-            i += 6;
-            int len = 0;
-            while (i +len < data.length && data[i +len] != 0)
-                ++len;
-            byte[] filenameBytes = new byte[len];
-            System.arraycopy(data, i, filenameBytes, 0, len);
-            i += len +1;
-            String fileName = new String(filenameBytes, Charset.defaultCharset());
-            byte []sha1 = new byte[20];
-            System.arraycopy(data, i, sha1, 0, 20);
-            i += 20;
-            tree.AddItem(GitObject.factory(new String(mode, Charset.defaultCharset()).toCharArray(), fileName, sha1));
-        }
-    }
+            public void run() {
+                PullHash(ci.GetTree());
+            }
 
-    public void FetchTree(final GitCommit ci, final OnResponseListener<GitObject.GitTree> response) {
-        PullHash(ci.GetTree(), new OnResponseListener<byte[]>() {
             @Override
             public void onResponse(byte[] result) {
-                GitObject.GitTree tree = new GitObject.GitTree(ci.GetTree()).Initialize();
-                FillTree(tree, result);
-                RecursiveFetchTree(tree, response);
+                FillTree(fCurrentTree, result);
+                fCurrentTree = fRoot.FindNextUninitialiazedTree();
+                if (fCurrentTree != null)
+                    PullHash(fCurrentTree.Initialize().GetHash());
+                else
+                    fResponseListener.onResponse(fRoot);
             }
 
             @Override
             public void onError(String msg, Throwable e) {
-                response.onError(msg, e);
+                fResponseListener.onError(msg, e);
+            }
+
+            private void PullHash(String hash) {
+                fResponseListener.onMsg("Reading tree " +hash);
+                DumbGitInterface.this.PullHash(hash, this);
+            }
+
+            private void FillTree(final GitObject.GitTree tree, byte[] data) {
+                int i = 0;
+
+                while (i < data.length) {
+                    byte[] mode = new byte[6];
+                    if (i +6 >= data.length)
+                        break;
+                    System.arraycopy(data, i, mode, 0, 6);
+                    i += 6;
+                    int len = 0;
+                    while (i +len < data.length && data[i +len] != 0)
+                        ++len;
+                    byte[] filenameBytes = new byte[len];
+                    System.arraycopy(data, i, filenameBytes, 0, len);
+                    i += len;
+                    String fileName = new String(filenameBytes, Charset.defaultCharset());
+                    if (i +21 > data.length)
+                        break;
+                    byte []sha1 = new byte[21];
+                    System.arraycopy(data, i, sha1, 0, 21);
+                    i += 21;
+                    tree.AddItem(GitObject.factory(new String(mode, Charset.defaultCharset()).toCharArray(), fileName, sha1ToString(sha1)));
+                }
             }
-       });
+
+            private String sha1ToString(byte[] sha1) {
+                String out = new BigInteger(1, sha1).toString(16);
+                if (out.length() == 40)
+                    return out;
+                StringBuilder sb = new StringBuilder();
+                for (int i = 40 -out.length(); i > 0; --i)
+                    sb.append('0');
+                return sb.toString() +out;
+            }
+        }
+
+        new RecursiveFetchTreeWalker(ci, response).run();
+    }
+
+    @Override
+    public void FetchBlob(final GitObject.GitBlob blob, final OnResponseListener<byte[]> response) {
+        PullHash(blob.GetHash(), response);
     }
 
-    public void Pull(final OnStreamResponseListener<Void> response) {
+    public void FetchTree(final OnStreamResponseListener<GitObject.GitTree> response) {
         GetRefs(new GitInterface.OnResponseListener<GitRef[]>() {
             @Override
             public void onResponse(final GitRef[] result) {
@@ -242,10 +279,16 @@ class DumbGitInterface implements GitInterface {
                             response.onMsg("Finished read commit");
                             response.onMsg(result.GetMessage());
                             response.onMsg("Reading tree #" +result.GetTree());
-                            FetchTree(result, new OnResponseListener<GitObject.GitTree>() {
+                            FetchTree(result, new OnStreamResponseListener<GitObject.GitTree>() {
+                                @Override
+                                public void onMsg(String message) {
+                                    response.onMsg(message);
+                                }
+
                                 @Override
                                 public void onResponse(GitObject.GitTree result) {
                                     response.onMsg("Finished read tree");
+                                    response.onResponse(result);
                                 }
 
                                 @Override
@@ -272,7 +315,7 @@ class DumbGitInterface implements GitInterface {
         });
     }
 
-    public void PullHash(String hash, final OnResponseListener<byte[]> response) {
+    private void PullHash(String hash, final OnResponseListener<byte[]> response) {
         URL url;
         try {
             url = new URL(fConfig.GetUrl() + "/objects/" + hash.substring(0, 2) + "/" + hash.substring(2));
@@ -281,16 +324,6 @@ class DumbGitInterface implements GitInterface {
             response.onError(e.getClass().getName() +": " +e.getMessage(), e);
             return;
         }
-        protoInflateGet(url, new OnResponseListener<byte[]>() {
-            @Override
-            public void onResponse(byte []result) {
-                response.onResponse(result);
-            }
-
-            @Override
-            public void onError(String msg, Throwable e) {
-                response.onError(msg, e);
-            }
-        });
+        protoInflateGet(url, response);
     }
 }

+ 4 - 4
app/src/main/java/info/knacki/pass/git/GitInterface.java

@@ -15,8 +15,8 @@ public interface GitInterface {
     }
 
     void GetRefs(OnResponseListener<GitRef[]> callback);
-    void Pull(OnStreamResponseListener<Void> response);
-    void FetchCommit(GitRef ref, final OnResponseListener<GitCommit> response);
-    void FetchTree(GitCommit ci, OnResponseListener<GitObject.GitTree> response);
-    void PullHash(String ref, OnResponseListener<byte[]> response);
+    void FetchCommit(GitRef ref, OnResponseListener<GitCommit> response);
+    void FetchTree(GitCommit ci, OnStreamResponseListener<GitObject.GitTree> response);
+    void FetchTree(OnStreamResponseListener<GitObject.GitTree> response);
+    void FetchBlob(GitObject.GitBlob blob, OnResponseListener<byte[]> response);
 }

+ 74 - 12
app/src/main/java/info/knacki/pass/git/entities/GitObject.java

@@ -1,54 +1,116 @@
 package info.knacki.pass.git.entities;
 
+import android.support.annotation.NonNull;
+
 import java.util.HashMap;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.logging.Logger;
 
-public class GitObject {
+public class GitObject implements Comparable<GitObject> {
     public final char[] fMode;
     public final String fName;
-    public final byte[] fSha1;
+    public final String fSha1;
+
+
+    @Override
+    public int compareTo(@NonNull GitObject gitObject) {
+        if ((this instanceof GitTree) && !(gitObject instanceof GitBlob))
+            return -1;
+        if (!(this instanceof GitTree) && (gitObject instanceof GitBlob))
+            return 1;
+        return fName.compareTo(gitObject.fName);
+    }
 
     public static class GitBlob extends GitObject {
-        private GitBlob(char[] mode, String name, byte []sha1) {
+        private GitBlob(char[] mode, String name, String sha1) {
             super(mode, name, sha1);
         }
     }
 
     public static class GitTree extends GitObject {
-        protected HashMap<String, GitObject> items = null;
+        protected HashMap<String, GitObject> fItems = null;
 
-        private GitTree(char[] mode, String name, byte []sha1) {
+        private GitTree(char[] mode, String name, String sha1) {
             super(mode, name, sha1);
         }
 
         public GitTree(String sha1) {
-            super(new char[] { '4', '0', '0', '0', '0' }, "", sha1.getBytes());
+            super(new char[] { '4', '0', '0', '0', '0' }, "", sha1);
         }
 
         public GitTree Initialize() {
-            items = new HashMap<>();
+            fItems = new HashMap<>();
             return this;
         }
 
         public boolean IsInitialized() {
-            return null != items;
+            return null != fItems;
+        }
+
+        public GitObject GetObject(String name) {
+            return fItems.get(name);
         }
 
         public GitTree AddItem(GitObject item) {
-            items.put(item.fName, item);
+            fItems.put(item.fName, item);
             return this;
         }
+
+        public GitTree FindNextUninitialiazedTree() {
+            if (!IsInitialized())
+                return this;
+            for (GitObject obj: fItems.values()) {
+                if (!(obj instanceof GitTree))
+                    continue;
+                GitTree child = ((GitTree) obj).FindNextUninitialiazedTree();
+                if (child != null)
+                    return child;
+            }
+            return null;
+        }
+
+        public Iterable<GitObject> objects() {
+            SortedSet<GitObject> objects = new TreeSet<>();
+            objects.addAll(fItems.values());
+            return objects;
+        }
+
+        public Iterable<GitBlob> GetBlobs() {
+            SortedSet<GitBlob> objects = new TreeSet<>();
+            for (GitObject i: fItems.values())
+                if (i instanceof GitBlob)
+                    objects.add((GitBlob) i);
+            return objects;
+        }
+
+        public Iterable<GitTree> GetTrees() {
+            SortedSet<GitTree> objects = new TreeSet<>();
+            for (GitObject i: fItems.values())
+                if (i instanceof GitTree)
+                    objects.add((GitTree) i);
+            return objects;
+        }
     }
 
-    private GitObject(char[] mode, String name, byte[] sha1) {
+    private GitObject(char[] mode, String name, String sha1) {
         fMode = mode;
         fName = name;
         fSha1 = sha1;
     }
 
-    public static GitObject factory(char[] mode, String name, byte[]sha1) {
+    public static GitObject factory(char[] mode, String name, String sha1) {
         if (mode[0] == '4') {
             return new GitTree(mode, name, sha1);
         }
-        return new GitBlob(mode, name, sha1);
+        return new GitBlob(mode, name.substring(1), sha1);
+    }
+
+    public String GetHash() {
+        return fSha1;
+    }
+
+    public String GetFilename() {
+        return fName;
     }
 }

+ 1 - 1
app/src/main/java/info/knacki/pass/settings/ui/SettingsActivity.java

@@ -21,7 +21,7 @@ import info.knacki.pass.R;
 import info.knacki.pass.git.GitInterface;
 import info.knacki.pass.git.GitInterfaceFactory;
 import info.knacki.pass.git.entities.GitRef;
-import info.knacki.pass.git.ui.GitPullActivity;
+import info.knacki.pass.ui.GitPullActivity;
 import info.knacki.pass.settings.SettingsManager;
 
 import java.util.HashMap;

+ 16 - 11
app/src/main/java/info/knacki/pass/git/ui/GitPullActivity.java → app/src/main/java/info/knacki/pass/ui/GitPullActivity.java

@@ -1,21 +1,24 @@
-package info.knacki.pass.git.ui;
+package info.knacki.pass.ui;
 
 import android.os.Bundle;
 import android.support.v7.app.AppCompatActivity;
 import android.widget.ProgressBar;
 import android.widget.TextView;
-import android.widget.Toast;
 
-import java.util.logging.Level;
+import java.nio.charset.Charset;
 import java.util.logging.Logger;
 
 import info.knacki.pass.R;
 import info.knacki.pass.git.GitInterface;
 import info.knacki.pass.git.GitInterfaceFactory;
+import info.knacki.pass.git.entities.GitObject;
 import info.knacki.pass.settings.SettingsManager;
 
 public class GitPullActivity extends AppCompatActivity {
 
+    private GitInterface fGitInterfage;
+    private GitObject.GitTree fTree;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -28,9 +31,9 @@ public class GitPullActivity extends AppCompatActivity {
             finish();
             return;
         }
-        GitInterface gitInterface = GitInterfaceFactory.factory(this, (SettingsManager.Git) versioning);
-        if (gitInterface != null) {
-            gitInterface.Pull(new GitInterface.OnStreamResponseListener<Void>() {
+        fGitInterfage = GitInterfaceFactory.factory(this, (SettingsManager.Git) versioning);
+        if (fGitInterfage != null) {
+            fGitInterfage.FetchTree(new GitInterface.OnStreamResponseListener<GitObject.GitTree>() {
                 @Override
                 public void onMsg(final String msg) {
                     GitPullActivity.this.runOnUiThread(new Runnable() {
@@ -43,14 +46,12 @@ public class GitPullActivity extends AppCompatActivity {
                 }
 
                 @Override
-                public void onResponse(Void result) {
+                public void onResponse(GitObject.GitTree result) {
+                    fTree = result;
                     GitPullActivity.this.runOnUiThread(new Runnable() {
                         @Override
                         public void run() {
-                            ProgressBar pg = findViewById(R.id.progressBar);
-                            pg.setIndeterminate(false);
-                            pg.setMax(1);
-                            pg.setProgress(1);
+                            GitPullActivity.this.OnTreeStructureFetched();
                         }
                     });
                 }
@@ -72,4 +73,8 @@ public class GitPullActivity extends AppCompatActivity {
             });
         }
     }
+
+    protected void OnTreeStructureFetched() {
+
+    }
 }

+ 3 - 3
app/src/main/java/info/knacki/pass/ui/MainActivity.java

@@ -1,9 +1,7 @@
 package info.knacki.pass.ui;
 
-import android.Manifest;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.support.v4.app.ActivityCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.os.Bundle;
 import android.view.Menu;
@@ -114,7 +112,6 @@ public class MainActivity extends AppCompatActivity implements PasswordClickList
     }
 
     void requestPermissions() {
-        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.INTERNET}, 1);
     }
 
     @Override
@@ -127,6 +124,9 @@ public class MainActivity extends AppCompatActivity implements PasswordClickList
         ((ScrollView)findViewById(R.id.passwordListContainer)).addView(vPasswordListView);
 
         requestPermissions();
+
+        startActivity(new Intent(this, GitPullActivity.class));
+
     }
 
     @Override