From d67d9da818e462751b8b6cefee5cfeea815ee251 Mon Sep 17 00:00:00 2001
From: zt515 <kiva515@foxmail.com>
Date: Sat, 4 Nov 2017 23:32:24 +0800
Subject: [PATCH] Fix: NeoPackageParser cannot handle multiline value

---
 .../io/neoterm/component/NeoInitializer.kt    |  4 +-
 .../component/pm/NeoPackageParser.java        | 44 ++++++++++++++++---
 ...geComponent.java => PackageComponent.java} |  2 +-
 .../frontend/component/ComponentManager.kt    | 33 ++++++++------
 .../component/ComponentNotFoundException.kt   |  2 +-
 .../neoterm/ui/pm/PackageManagerActivity.kt   | 12 ++---
 .../java/io/neoterm/PackageManagerTest.kt     | 31 +++++++++++++
 app/src/test/java/io/neoterm/SourceUrlTest.kt | 15 -------
 .../test/java/io/neoterm/TestInitializer.kt   |  4 +-
 9 files changed, 96 insertions(+), 51 deletions(-)
 rename app/src/main/java/io/neoterm/component/pm/{NeoPackageComponent.java => PackageComponent.java} (98%)
 create mode 100644 app/src/test/java/io/neoterm/PackageManagerTest.kt
 delete mode 100644 app/src/test/java/io/neoterm/SourceUrlTest.kt

diff --git a/app/src/main/java/io/neoterm/component/NeoInitializer.kt b/app/src/main/java/io/neoterm/component/NeoInitializer.kt
index 1a99c9e..797c032 100644
--- a/app/src/main/java/io/neoterm/component/NeoInitializer.kt
+++ b/app/src/main/java/io/neoterm/component/NeoInitializer.kt
@@ -7,7 +7,7 @@ import io.neoterm.component.completion.CompletionComponent
 import io.neoterm.component.config.ConfigureComponent
 import io.neoterm.component.eks.ExtraKeysComponent
 import io.neoterm.component.font.FontComponent
-import io.neoterm.component.pm.NeoPackageComponent
+import io.neoterm.component.pm.PackageComponent
 import io.neoterm.component.script.UserScriptComponent
 import io.neoterm.frontend.logging.NLog
 import io.neoterm.frontend.component.ComponentManager
@@ -25,6 +25,6 @@ object NeoInitializer {
         ComponentManager.registerComponent(UserScriptComponent::class.java)
         ComponentManager.registerComponent(ExtraKeysComponent::class.java)
         ComponentManager.registerComponent(CompletionComponent::class.java)
-        ComponentManager.registerComponent(NeoPackageComponent::class.java)
+        ComponentManager.registerComponent(PackageComponent::class.java)
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/io/neoterm/component/pm/NeoPackageParser.java b/app/src/main/java/io/neoterm/component/pm/NeoPackageParser.java
index 9dd6e0f..c13007e 100644
--- a/app/src/main/java/io/neoterm/component/pm/NeoPackageParser.java
+++ b/app/src/main/java/io/neoterm/component/pm/NeoPackageParser.java
@@ -56,8 +56,9 @@ public class NeoPackageParser {
 
         String line;
         String[] splits = new String[2];
-        String key;
-        String value;
+        String key = null;
+        String value = null;
+        boolean appendMode = false;
 
         NeoPackageInfo packageInfo = null;
 
@@ -67,9 +68,19 @@ public class NeoPackageParser {
                 continue;
             }
 
-            splitKeyAndValue(line, splits);
-            key = splits[0];
-            value = splits[1];
+            if (splitKeyAndValue(line, splits)) {
+                key = splits[0];
+                value = splits[1];
+                appendMode = false;
+            } else {
+                if (key == null) {
+                    // no key provided, we don't know where the value should be appended to
+                    continue;
+                }
+                // the rest value to previous key
+                value = line.trim();
+                appendMode = true;
+            }
 
             if (key.equals(KEY_PACKAGE_NAME)) {
                 if (packageInfo != null) {
@@ -84,6 +95,10 @@ public class NeoPackageParser {
                 continue;
             }
 
+            if (appendMode) {
+                value = appendToLastValue(packageInfo, key, value);
+            }
+
             switch (key) {
                 case KEY_ARCH:
                     packageInfo.setArchitecture(Architecture.Companion.parse(value));
@@ -132,9 +147,24 @@ public class NeoPackageParser {
         stateListener.onEndState();
     }
 
-    private void splitKeyAndValue(String line, String[] splits) {
-        splits[0] = line.substring(0, line.indexOf(':')).trim();
+    private String appendToLastValue(NeoPackageInfo packageInfo, String key, String value) {
+        // Currently, only descriptions can be multiline
+        switch (key) {
+            case KEY_DESC:
+                return packageInfo.getDescription() + " " + value;
+            default:
+                return value;
+        }
+    }
+
+    private boolean splitKeyAndValue(String line, String[] splits) {
         int valueIndex = line.indexOf(':');
+        if (valueIndex < 0) {
+            return false;
+        }
+
+        splits[0] = line.substring(0, valueIndex).trim();
         splits[1] = line.substring(valueIndex == line.length() ? valueIndex : valueIndex + 1).trim();
+        return true;
     }
 }
diff --git a/app/src/main/java/io/neoterm/component/pm/NeoPackageComponent.java b/app/src/main/java/io/neoterm/component/pm/PackageComponent.java
similarity index 98%
rename from app/src/main/java/io/neoterm/component/pm/NeoPackageComponent.java
rename to app/src/main/java/io/neoterm/component/pm/PackageComponent.java
index 3858bb4..5d828e9 100644
--- a/app/src/main/java/io/neoterm/component/pm/NeoPackageComponent.java
+++ b/app/src/main/java/io/neoterm/component/pm/PackageComponent.java
@@ -11,7 +11,7 @@ import io.neoterm.frontend.component.NeoComponent;
  * @author kiva
  */
 
-public class NeoPackageComponent implements NeoComponent {
+public class PackageComponent implements NeoComponent {
     private final Object lock = new Object();
     private boolean isRefreshing = false;
     private boolean queryEnabled = true;
diff --git a/app/src/main/java/io/neoterm/frontend/component/ComponentManager.kt b/app/src/main/java/io/neoterm/frontend/component/ComponentManager.kt
index dbc85c0..51331fc 100644
--- a/app/src/main/java/io/neoterm/frontend/component/ComponentManager.kt
+++ b/app/src/main/java/io/neoterm/frontend/component/ComponentManager.kt
@@ -6,32 +6,37 @@ import java.util.concurrent.ConcurrentHashMap
  * @author kiva
  */
 object ComponentManager {
-    val COMPONENTS = ConcurrentHashMap<Class<out NeoComponent>, NeoComponent>()
+    private val COMPONENTS = ConcurrentHashMap<Class<out NeoComponent>, NeoComponent>()
 
-    fun registerComponent(serviceClass: Class<out NeoComponent>) {
-        if (COMPONENTS.containsKey(serviceClass)) {
-            throw ComponentDuplicateException(serviceClass.simpleName)
+    fun registerComponent(componentClass: Class<out NeoComponent>) {
+        if (COMPONENTS.containsKey(componentClass)) {
+            throw ComponentDuplicateException(componentClass.simpleName)
         }
-        val service = createServiceInstance(serviceClass)
-        COMPONENTS.put(serviceClass, service)
+        val service = createServiceInstance(componentClass)
+        COMPONENTS.put(componentClass, service)
         service.onServiceInit()
     }
 
-    fun unregisterComponent(serviceInterface: Class<out NeoComponent>) {
-        val service = COMPONENTS[serviceInterface]
+    fun unregisterComponent(componentInterface: Class<out NeoComponent>) {
+        val service = COMPONENTS[componentInterface]
         if (service != null) {
             service.onServiceDestroy()
-            COMPONENTS.remove(serviceInterface)
+            COMPONENTS.remove(componentInterface)
         }
     }
 
+    @Suppress("UNCHECKED_CAST")
+    fun <T : NeoComponent> getComponent(componentInterface: Class<T>) : T {
+        val service: NeoComponent = COMPONENTS[componentInterface] ?:
+                throw ComponentNotFoundException(componentInterface.simpleName)
+
+        service.onServiceObtained()
+        return service as T
+    }
+
     inline fun <reified T : NeoComponent> getComponent(): T {
         val serviceInterface = T::class.java
-        val service: NeoComponent = COMPONENTS[serviceInterface] ?:
-                throw ComponentNotFoundException(serviceInterface.simpleName)
-
-        service.onServiceObtained()
-        return service as T
+        return getComponent(serviceInterface);
     }
 
     private fun createServiceInstance(serviceInterface: Class<out NeoComponent>): NeoComponent {
diff --git a/app/src/main/java/io/neoterm/frontend/component/ComponentNotFoundException.kt b/app/src/main/java/io/neoterm/frontend/component/ComponentNotFoundException.kt
index b54e3c6..d7289ce 100644
--- a/app/src/main/java/io/neoterm/frontend/component/ComponentNotFoundException.kt
+++ b/app/src/main/java/io/neoterm/frontend/component/ComponentNotFoundException.kt
@@ -3,5 +3,5 @@ package io.neoterm.frontend.component
 /**
  * @author kiva
  */
-class ComponentNotFoundException(serviceName: String) : RuntimeException("Service `$serviceName' not found") {
+class ComponentNotFoundException(serviceName: String) : RuntimeException("Component `$serviceName' not found") {
 }
\ No newline at end of file
diff --git a/app/src/main/java/io/neoterm/ui/pm/PackageManagerActivity.kt b/app/src/main/java/io/neoterm/ui/pm/PackageManagerActivity.kt
index 0d047e0..61f53be 100644
--- a/app/src/main/java/io/neoterm/ui/pm/PackageManagerActivity.kt
+++ b/app/src/main/java/io/neoterm/ui/pm/PackageManagerActivity.kt
@@ -1,8 +1,5 @@
 package io.neoterm.ui.pm
 
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.ObjectAnimator
 import android.os.Bundle
 import android.support.v4.view.MenuItemCompat
 import android.support.v7.app.AlertDialog
@@ -13,15 +10,12 @@ import android.support.v7.widget.SearchView
 import android.support.v7.widget.Toolbar
 import android.view.Menu
 import android.view.MenuItem
-import android.view.View
-import android.view.animation.AccelerateDecelerateInterpolator
 import android.widget.EditText
-import android.widget.ProgressBar
 import android.widget.Toast
 import com.github.wrdlbrnft.sortedlistadapter.SortedListAdapter
 import io.neoterm.R
 import io.neoterm.backend.TerminalSession
-import io.neoterm.component.pm.NeoPackageComponent
+import io.neoterm.component.pm.PackageComponent
 import io.neoterm.component.pm.SourceManager
 import io.neoterm.component.pm.SourceUtils
 import io.neoterm.frontend.component.ComponentManager
@@ -114,7 +108,7 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
     }
 
     private fun changeSource() {
-        val sourceManager = ComponentManager.getComponent<NeoPackageComponent>().sourceManager
+        val sourceManager = ComponentManager.getComponent<PackageComponent>().sourceManager
         val sourceList = sourceManager.sources
 
         val currentSource = NeoPreference.loadString(R.string.key_package_source, NeoTermPath.DEFAULT_SOURCE)
@@ -196,7 +190,7 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
     private fun refreshPackageList() {
         models.clear()
         Thread {
-            val pm = ComponentManager.getComponent<NeoPackageComponent>()
+            val pm = ComponentManager.getComponent<PackageComponent>()
             val sourceFiles = SourceUtils.detectSourceFiles()
 
             pm.clearPackages()
diff --git a/app/src/test/java/io/neoterm/PackageManagerTest.kt b/app/src/test/java/io/neoterm/PackageManagerTest.kt
new file mode 100644
index 0000000..16ffa6c
--- /dev/null
+++ b/app/src/test/java/io/neoterm/PackageManagerTest.kt
@@ -0,0 +1,31 @@
+package io.neoterm
+
+import io.neoterm.component.pm.PackageComponent
+import io.neoterm.component.pm.SourceUtils
+import io.neoterm.frontend.component.ComponentManager
+import org.junit.Test
+import java.io.File
+
+/**
+ * @author kiva
+ */
+class PackageManagerTest {
+    @Test
+    fun testSourceUrl() {
+        val url = "http://7sp0th.iok.la:81/neoterm"
+        println(SourceUtils.detectSourceFilePrefix(url))
+    }
+
+    @Test
+    fun testMultilineInListFile() {
+        try {
+            ComponentManager.registerComponent(PackageComponent::class.java)
+        } catch (ignore: Throwable) {
+        }
+
+        val pm = ComponentManager.getComponent<PackageComponent>();
+        pm.reloadPackages(File("/Users/kiva/1"), false)
+
+        System.err.println(pm.packages["rcs"]?.description)
+    }
+}
\ No newline at end of file
diff --git a/app/src/test/java/io/neoterm/SourceUrlTest.kt b/app/src/test/java/io/neoterm/SourceUrlTest.kt
deleted file mode 100644
index 55a7785..0000000
--- a/app/src/test/java/io/neoterm/SourceUrlTest.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.neoterm
-
-import io.neoterm.component.pm.SourceUtils
-import org.junit.Test
-
-/**
- * @author kiva
- */
-class SourceUrlTest {
-    @Test
-    fun testSourceUrl() {
-        val url = "http://7sp0th.iok.la:81/neoterm"
-        println(SourceUtils.detectSourceFilePrefix(url))
-    }
-}
\ No newline at end of file
diff --git a/app/src/test/java/io/neoterm/TestInitializer.kt b/app/src/test/java/io/neoterm/TestInitializer.kt
index 3d4b7d2..d9d49ab 100644
--- a/app/src/test/java/io/neoterm/TestInitializer.kt
+++ b/app/src/test/java/io/neoterm/TestInitializer.kt
@@ -6,7 +6,7 @@ import io.neoterm.component.completion.CompletionComponent
 import io.neoterm.component.config.ConfigureComponent
 import io.neoterm.component.eks.ExtraKeysComponent
 import io.neoterm.component.font.FontComponent
-import io.neoterm.component.pm.NeoPackageComponent
+import io.neoterm.component.pm.PackageComponent
 import io.neoterm.component.script.UserScriptComponent
 import io.neoterm.frontend.component.ComponentManager
 
@@ -22,6 +22,6 @@ object TestInitializer {
         ComponentManager.registerComponent(UserScriptComponent::class.java)
         ComponentManager.registerComponent(ExtraKeysComponent::class.java)
         ComponentManager.registerComponent(CompletionComponent::class.java)
-        ComponentManager.registerComponent(NeoPackageComponent::class.java)
+        ComponentManager.registerComponent(PackageComponent::class.java)
     }
 }
\ No newline at end of file