├── .gitignore
├── gfx
├── main-ui.png
├── main-ui-update.png
├── main-ui-no-update.png
├── main-ui-select-project.png
├── main-ui-update-finished.png
├── main-ui-project-selected.png
├── main-ui-select-wrong-project.png
├── main-ui-update-in-progress-2.png
└── main-ui-update-in-progress.png
├── images
└── showcase.JPG
├── src
└── main
│ ├── lib
│ └── jfxrt.jar
│ ├── resources
│ ├── polar_upgrade_1024.png
│ ├── applicationUI.fxml
│ └── aboutUI.fxml
│ └── java
│ └── com
│ └── afollestad
│ └── polarupgradetool
│ ├── jfx
│ ├── InterfaceUpdateThread.kt
│ ├── UICallback.kt
│ ├── AboutScene.kt
│ ├── UpgradeTool.kt
│ └── WindowScene.kt
│ ├── utils
│ ├── SecurityUtil.kt
│ ├── UpdateUtils.kt
│ ├── UrlUtils.kt
│ ├── UnzipUtil.kt
│ ├── Util.kt
│ ├── ZipUtil.kt
│ ├── ManifestUtils.kt
│ └── FileUtil.kt
│ ├── xml
│ ├── XmlElementExtractor.kt
│ ├── XmlScanner.kt
│ └── XmlMigrator.kt
│ ├── GradleMigrator.kt
│ ├── AttributeExtractor.kt
│ ├── MainBase.kt
│ └── Main.kt
├── polarupgradetool-1.0.10.jar
├── README.md
├── dependency-reduced-pom.xml
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/*
2 | gfx/icons/*
3 | target/*
4 | *.iml
--------------------------------------------------------------------------------
/gfx/main-ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/gfx/main-ui.png
--------------------------------------------------------------------------------
/images/showcase.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/images/showcase.JPG
--------------------------------------------------------------------------------
/gfx/main-ui-update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/gfx/main-ui-update.png
--------------------------------------------------------------------------------
/src/main/lib/jfxrt.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/src/main/lib/jfxrt.jar
--------------------------------------------------------------------------------
/gfx/main-ui-no-update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/gfx/main-ui-no-update.png
--------------------------------------------------------------------------------
/polarupgradetool-1.0.10.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/polarupgradetool-1.0.10.jar
--------------------------------------------------------------------------------
/gfx/main-ui-select-project.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/gfx/main-ui-select-project.png
--------------------------------------------------------------------------------
/gfx/main-ui-update-finished.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/gfx/main-ui-update-finished.png
--------------------------------------------------------------------------------
/gfx/main-ui-project-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/gfx/main-ui-project-selected.png
--------------------------------------------------------------------------------
/gfx/main-ui-select-wrong-project.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/gfx/main-ui-select-wrong-project.png
--------------------------------------------------------------------------------
/gfx/main-ui-update-in-progress-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/gfx/main-ui-update-in-progress-2.png
--------------------------------------------------------------------------------
/gfx/main-ui-update-in-progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/gfx/main-ui-update-in-progress.png
--------------------------------------------------------------------------------
/src/main/resources/polar_upgrade_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PDDStudio/polar-dashboard-upgrade-tool/master/src/main/resources/polar_upgrade_1024.png
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/jfx/InterfaceUpdateThread.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.jfx
2 |
3 | import com.afollestad.polarupgradetool.Main
4 |
5 | /**
6 | * Project : polar-dashboard-upgrade-tool
7 | * Author : pddstudio
8 | * Year : 2016
9 | */
10 | class InterfaceUpdateThread(internal val location: String, internal val uiCallback: UICallback) : Thread(), Runnable {
11 |
12 | override fun run() {
13 | Main.upgrade(location, uiCallback)
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/jfx/UICallback.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.jfx
2 |
3 | /**
4 | * Project : polar-dashboard-upgrade-tool
5 | * Author : pddstudio
6 | * Year : 2016
7 | */
8 | interface UICallback {
9 |
10 | fun onProjectDetected(applicationName: String, applicationPackage: String, applicationVersionName: String, applicationVersionCode: String)
11 |
12 | fun onErrorOccurred(errorMessage: String)
13 |
14 | fun onArchiveDownloadStarted(sizeStr: String)
15 |
16 | fun onArchiveDownloadProgress(progressStr: String)
17 |
18 | fun onArchiveDownloadFailed(errorMessage: String)
19 |
20 | fun onArchiveDownloadSuccess()
21 |
22 | fun onStatusUpdate(statusMessage: String)
23 |
24 | fun onUpdateSuccessful()
25 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/utils/SecurityUtil.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.utils
2 |
3 | import com.afollestad.polarupgradetool.Main
4 |
5 | import java.io.File
6 |
7 | /**
8 | * Project : polarupgradetool
9 | * Author : pddstudio
10 | * Year : 2016
11 | */
12 | object SecurityUtil {
13 |
14 | private val DEV_CUSTOM = "dev_customization.xml"
15 | private val DEV_THEMING = "dev_theming.xml"
16 |
17 | fun checkIsPolarBased(basePath: String): Boolean {
18 | val resources = File(basePath + Main.VALUES_FOLDER_PATH)
19 | if (!resources.exists() || !resources.isDirectory || resources.listFiles() == null || resources.listFiles()!!.size <= 0) return false
20 | for (file in resources.listFiles()!!) {
21 | if (file.name == DEV_CUSTOM || file.name == DEV_THEMING) return true
22 | }
23 | return false
24 | }
25 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/utils/UpdateUtils.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.utils
2 |
3 | /**
4 | * Project : polarupgradetool
5 | * Author : pddstudio
6 | * Year : 2016
7 | */
8 | class UpdateUtils private constructor(private val updateCallback: UpdateUtils.UpdateCallback) {
9 |
10 | interface UpdateCallback {
11 | fun onUpdateCheckStarted()
12 |
13 | fun onUpdateCheckFailed(errorMsg: String)
14 |
15 | fun onUpdateCheckFinished(currentVersion: String, latestVersion: String)
16 | }
17 |
18 | fun execute() {
19 | UpdateThread().start()
20 | }
21 |
22 | private inner class UpdateThread : Thread(), Runnable {
23 |
24 | override fun run() {
25 | updateCallback.onUpdateCheckStarted()
26 | val pom = ManifestUtils.remoteApplicationModel
27 | if (pom == null) {
28 | updateCallback.onUpdateCheckFailed("Unable to resolve external pom model.")
29 | this.interrupt()
30 | } else if (!isInterrupted) {
31 | val currentVersion = ManifestUtils.getApplicationVersion(UpdateUtils::class.java)
32 | val externalVersion = pom.version
33 | updateCallback.onUpdateCheckFinished(currentVersion, externalVersion)
34 | }
35 | }
36 | }
37 |
38 | companion object {
39 | fun checkForUpdate(updateCallback: UpdateCallback): UpdateUtils {
40 | return UpdateUtils(updateCallback)
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/utils/UrlUtils.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.utils
2 |
3 | import com.afollestad.polarupgradetool.jfx.UpgradeTool
4 |
5 | /**
6 | * Project : polarupgradetool
7 | * Author : pddstudio
8 | * Year : 2016
9 | */
10 | object UrlUtils {
11 |
12 | private val URL_GITHUB_PUT = "https://github.com/afollestad/polar-dashboard-upgrade-tool"
13 | private val URL_GITHUB_POLAR = "https://github.com/afollestad/polar-dashboard"
14 | private val URL_GITHUB_AFOLLESTAD = "https://github.com/afollestad"
15 | private val URL_GITHUB_PDDSTUDIO = "https://github.com/PDDStudio"
16 | private val URL_GITHUB_WIKI = "https://github.com/PDDStudio/polar-dashboard-upgrade-tool/wiki/Polar-Dashboard-Upgrade-Tool---Wiki"
17 | private val URL_GITHUB_RELEASES = "https://github.com/afollestad/polar-dashboard-upgrade-tool/releases"
18 |
19 | fun openPolarUpgradeToolPage() {
20 | UpgradeTool.hostService?.showDocument(URL_GITHUB_PUT)
21 | }
22 |
23 | fun openPolarPage() {
24 | UpgradeTool.hostService?.showDocument(URL_GITHUB_POLAR)
25 | }
26 |
27 | fun openAfollestadGithubPage() {
28 | UpgradeTool.hostService?.showDocument(URL_GITHUB_AFOLLESTAD)
29 | }
30 |
31 | fun openPddstudioGithubPage() {
32 | UpgradeTool.hostService?.showDocument(URL_GITHUB_PDDSTUDIO)
33 | }
34 |
35 | fun openWikiPage() {
36 | UpgradeTool.hostService?.showDocument(URL_GITHUB_WIKI)
37 | }
38 |
39 | fun openReleasePage() {
40 | UpgradeTool.hostService?.showDocument(URL_GITHUB_RELEASES)
41 | }
42 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Polar Upgrade Tool
2 |
3 |
5 |
6 | PUT allows you to automatically migrate your icon packs to the latest versions of Polar, without any manual copying. **This project does not migrate your project to Polar from other dashboard templates, it upgrades existing Polar-using icon packs.**
7 |
8 | See [Polar's main repository](https://github.com/afollestad/polar-dashboard) for information about Polar.
9 |
10 | PUT was designed and developed by [Aidan Follestad](https://github.com/afollestad) and
11 | [Patrick J](https://github.com/PDDStudio). The icon was designed by [Anthony Nguyen](https://plus.google.com/+AHNguyen).
12 |
13 | # Download & Wiki
14 | You can find the latest version of PUT's packaged binary in the [Release Page of this Repository](https://github.com/afollestad/polar-dashboard-upgrade-tool/releases).
15 |
16 | In case you need more information about how to use this Tool head over to the [Wiki Page](https://github.com/PDDStudio/polar-dashboard-upgrade-tool/wiki/Polar-Dashboard-Upgrade-Tool---Wiki).
17 |
18 | There is also some information about the upgrade tool on [Polar's Web Guide](http://afollestad.github.io/polar-dashboard/upgrades.html).
19 |
20 | The Wiki should guide people which are not common with technical/development stuff through the whole process to get their Polar-using icon pack updated.
21 |
22 | # Building and Running
23 |
24 | ### Windows
25 |
26 | From the project root:
27 |
28 | ```Gradle
29 | build-and-deploy.bat
30 | ```
31 |
32 | This will create a JAR in the `target` folder that you can execute.
33 |
34 | ### Unix (OSX) and Linux
35 |
36 | From the project root:
37 |
38 | ```Gradle
39 | ./build-and-deploy.sh
40 | ```
41 |
42 | This will create a JAR in the `target` folder that you can execute.
43 |
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/utils/UnzipUtil.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.utils
2 |
3 | import java.io.*
4 | import java.util.zip.ZipEntry
5 | import java.util.zip.ZipInputStream
6 |
7 | /**
8 | * @author Aidan Follestad (afollestad)
9 | */
10 | object UnzipUtil {
11 |
12 | private val BUFFER_SIZE = 4096
13 |
14 | @SuppressWarnings("ResultOfMethodCallIgnored")
15 | @Throws(IOException::class)
16 | fun unzip(zipFilePath: String, destDirectory: String) {
17 | val destDir = File(destDirectory)
18 | if (!destDir.exists())
19 | destDir.mkdir()
20 | val zipIn = ZipInputStream(FileInputStream(zipFilePath))
21 | var entry: ZipEntry? = zipIn.nextEntry
22 | // iterates over entries in the zip file
23 | while (entry != null) {
24 | val filePath = destDirectory + File.separator + entry.name
25 | if (!entry.isDirectory) {
26 | // if the entry is a file, extracts it
27 | extractFile(zipIn, filePath)
28 | } else {
29 | // if the entry is a directory, make the directory
30 | val dir = File(filePath)
31 | dir.mkdir()
32 | }
33 | zipIn.closeEntry()
34 | entry = zipIn.nextEntry
35 | }
36 | zipIn.close()
37 | }
38 |
39 | @Throws(IOException::class)
40 | private fun extractFile(zipIn: ZipInputStream, filePath: String) {
41 | var bos: BufferedOutputStream? = null
42 | try {
43 | bos = BufferedOutputStream(FileOutputStream(filePath))
44 | val bytesIn = ByteArray(BUFFER_SIZE)
45 | var read: Int
46 | while (true) {
47 | read = zipIn.read(bytesIn);
48 | if (read == -1) break;
49 | bos.write(bytesIn, 0, read);
50 | }
51 | } finally {
52 | Util.closeQuietely(bos)
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/jfx/AboutScene.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.jfx
2 |
3 | import com.afollestad.polarupgradetool.utils.ManifestUtils
4 | import com.afollestad.polarupgradetool.utils.UrlUtils
5 | import javafx.fxml.FXML
6 | import javafx.fxml.FXMLLoader
7 | import javafx.scene.Scene
8 | import javafx.scene.control.Label
9 | import javafx.scene.layout.VBox
10 |
11 | import java.io.IOException
12 |
13 | /**
14 | * Project : polarupgradetool
15 | * Author : pddstudio
16 | * Year : 2016
17 | */
18 | class AboutScene {
19 |
20 | var scene: Scene
21 | private val aboutSceneController: AboutSceneController
22 |
23 | init {
24 | aboutSceneController = AboutSceneController()
25 | scene = Scene(aboutSceneController)
26 | aboutSceneController.setRootScene(scene)
27 | }
28 |
29 | private inner class AboutSceneController internal constructor() : VBox() {
30 |
31 | @FXML private val projectVersionLabel: Label? = null
32 |
33 | init {
34 | try {
35 | val fxmlLoader = FXMLLoader(javaClass.getResource("/aboutUI.fxml"))
36 | fxmlLoader.setRoot(this)
37 | fxmlLoader.setController(this)
38 | fxmlLoader.load()
39 | projectVersionLabel!!.text = "Version " + ManifestUtils.getApplicationVersion(javaClass)
40 | } catch (io: IOException) {
41 | io.printStackTrace()
42 | }
43 |
44 | }
45 |
46 | fun setRootScene(scene: Scene) {
47 | this@AboutScene.scene = scene
48 | }
49 |
50 | @FXML
51 | protected fun openGitProfileAidan() {
52 | UrlUtils.openAfollestadGithubPage()
53 | }
54 |
55 | @FXML
56 | protected fun openGitProfilePatrick() {
57 | UrlUtils.openPddstudioGithubPage()
58 | }
59 |
60 | @FXML
61 | protected fun openGitPUT() {
62 | UrlUtils.openPolarUpgradeToolPage()
63 | }
64 |
65 | @FXML
66 | protected fun openGitPolar() {
67 | UrlUtils.openPolarPage()
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/xml/XmlElementExtractor.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.xml
2 |
3 | import com.afollestad.polarupgradetool.AttributeExtractor
4 | import com.afollestad.polarupgradetool.MainBase
5 | import com.afollestad.polarupgradetool.jfx.UICallback
6 | import java.io.File
7 | import java.nio.charset.Charset
8 | import java.util.*
9 | import java.util.regex.Pattern
10 |
11 | /**
12 | * @author Aidan Follestad (afollestad)
13 | */
14 | class XmlElementExtractor(private val mFile: File, tagNames: Array?, names: Array?, private val uiCallback: UICallback?) {
15 |
16 | private val REGEX = "<%s name=\"%s\">[\\s\\S\\n]*<\\/%s>"
17 | private val mPatterns: Array
18 |
19 | init {
20 | if (tagNames == null || names == null || tagNames.size != names.size)
21 | throw IllegalArgumentException("tagNames and names must be non-null matching length arrays.")
22 | mPatterns = Array(tagNames.size, {
23 | it ->
24 | Pattern.compile(REGEX.format(tagNames[it], names[it], tagNames[it]))
25 | })
26 | }
27 |
28 | fun find(): HashMap? {
29 | if (!mFile.exists()) {
30 | MainBase.LOG("[ERROR]: File ${mFile.absolutePath} does not exist.")
31 | uiCallback?.onErrorOccurred("File does not exist: ${mFile.absoluteFile}")
32 | return null
33 | }
34 |
35 | val result = HashMap(mPatterns.size)
36 |
37 | try {
38 | mFile.forEachLine(Charset.forName("UTF-8"), {
39 | for (p in mPatterns) {
40 | val matcher = p.matcher(it)
41 | if (matcher.find()) {
42 | val name = AttributeExtractor.getAttributeValue("name", it)
43 | val value = AttributeExtractor.getElementValue(it)
44 | result.put(name!!, value!!)
45 | break
46 | }
47 | }
48 | })
49 | } catch (e: Exception) {
50 | MainBase.LOG("[ERROR] Failed to read ${mFile.absolutePath}: ${e.message}")
51 | uiCallback?.onErrorOccurred("Failed to read ${mFile.absolutePath}: ${e.message}")
52 | e.printStackTrace()
53 | return null
54 | }
55 |
56 | return result
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/utils/Util.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.utils
2 |
3 | import java.io.Closeable
4 | import java.io.File
5 | import java.math.RoundingMode
6 | import java.text.DecimalFormat
7 |
8 | /**
9 | * @author Aidan Follestad (afollestad)
10 | */
11 | object Util {
12 |
13 | fun closeQuietely(c: Closeable?) {
14 | if (c == null) return
15 | try {
16 | c.close()
17 | } catch (ignored: Throwable) {
18 | }
19 |
20 | }
21 |
22 | fun round(value: Double): String {
23 | val df = DecimalFormat("#.##")
24 | df.roundingMode = RoundingMode.CEILING
25 | return df.format(value)
26 | }
27 |
28 | fun round(value: Float): String {
29 | val df = DecimalFormat("#.##")
30 | df.roundingMode = RoundingMode.CEILING
31 | return df.format(value.toDouble())
32 | }
33 |
34 | fun readableFileSizeMB(size: Long): String {
35 | val value = size.toDouble() / 1000000
36 | return "%sMB".format(round(value))
37 | }
38 |
39 | fun detectCodePackage(folder: File): String {
40 | var javaFolder = folder
41 | var pkg = ""
42 |
43 | var contents: Array? = javaFolder.listFiles() ?: return pkg
44 | // com
45 | javaFolder = contents!![0]
46 | pkg += javaFolder.name
47 |
48 | contents = javaFolder.listFiles()
49 | if (contents == null) return pkg
50 | // afollestad
51 | javaFolder = contents[0]
52 | pkg += "." + javaFolder.name
53 |
54 | contents = javaFolder.listFiles()
55 | if (contents == null) return pkg
56 | // polar
57 | javaFolder = contents[0]
58 | pkg += "." + javaFolder.name
59 |
60 | return pkg
61 | }
62 |
63 | fun skipPackage(folder: File): File {
64 | var javaFolder = folder
65 | var contents: Array? = javaFolder.listFiles() ?: return javaFolder
66 | // com
67 | javaFolder = contents!![0]
68 |
69 | contents = javaFolder.listFiles()
70 | if (contents == null) return javaFolder
71 | // afollestad
72 | javaFolder = contents[0]
73 |
74 | contents = javaFolder.listFiles()
75 | if (contents == null) return javaFolder
76 | // polar
77 | javaFolder = contents[0]
78 |
79 | return javaFolder
80 | }
81 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/utils/ZipUtil.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.utils
2 |
3 | import com.afollestad.polarupgradetool.MainBase
4 | import java.io.File
5 | import java.io.FileOutputStream
6 | import java.util.*
7 | import java.util.zip.ZipEntry
8 | import java.util.zip.ZipOutputStream
9 |
10 | /**
11 | * @author Aidan Follestad (afollestad)
12 | */
13 | object ZipUtil {
14 |
15 | private fun getAllFiles(dir: File): ArrayList {
16 | val fileList = ArrayList()
17 | val files = dir.listFiles() ?: return fileList
18 | for (file in files) {
19 | if ((file.name == ".git" || file.name == ".idea" ||
20 | file.name == ".gradle" || file.name == "build" ||
21 | file.name == ".DS_Store" || file.name.endsWith(".db")) && file.isDirectory) {
22 | continue
23 | }
24 | fileList.add(file)
25 | if (file.isDirectory)
26 | fileList.addAll(getAllFiles(file))
27 | }
28 | return fileList
29 | }
30 |
31 | @Throws(Exception::class)
32 | fun writeZipFile(directoryToZip: File, destZipFile: File) {
33 | var fos: FileOutputStream? = null
34 | var zos: ZipOutputStream? = null
35 | val files = getAllFiles(directoryToZip)
36 | try {
37 | fos = FileOutputStream(destZipFile)
38 | zos = ZipOutputStream(fos)
39 | for (file in files) {
40 | if (!file.isDirectory) {
41 | // we only zip files, not directories
42 | addToZip(directoryToZip, file, zos)
43 | }
44 | }
45 | } finally {
46 | Util.closeQuietely(zos)
47 | Util.closeQuietely(fos)
48 | }
49 | }
50 |
51 | @Throws(Exception::class)
52 | private fun addToZip(directoryToZip: File, file: File, zos: ZipOutputStream) {
53 | // we want the zipEntry's path to be a relative path that is relative
54 | // to the directory being zipped, so chop off the rest of the path
55 | val zipFilePath = file.canonicalPath.substring(directoryToZip.canonicalPath.length + 1,
56 | file.canonicalPath.length)
57 | MainBase.LOG("[ZIP]: $zipFilePath")
58 | val zipEntry = ZipEntry(zipFilePath)
59 | zos.putNextEntry(zipEntry)
60 | file.forEachBlock { bytes, size ->
61 | zos.write(bytes, 0, size)
62 | }
63 | zos.closeEntry()
64 | }
65 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/GradleMigrator.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool
2 |
3 | import com.afollestad.polarupgradetool.jfx.UICallback
4 | import com.afollestad.polarupgradetool.utils.Util
5 | import java.io.*
6 | import java.nio.charset.Charset
7 | import java.util.*
8 |
9 | /**
10 | * @author Aidan Follestad (afollestad)
11 | */
12 | class GradleMigrator(private val mProject: File, private val mLatest: File, private val uiCallback: UICallback?) {
13 |
14 | private fun processLineProperty(propertyName: String, line: String, propertyValue: String): String {
15 | val start = line.indexOf("$propertyName ")
16 | if (start == -1) return line
17 | return " $propertyName $propertyValue"
18 | }
19 |
20 | @SuppressWarnings("ResultOfMethodCallIgnored")
21 | fun process(): Boolean {
22 | val lines = ArrayList()
23 | try {
24 | mLatest.forEachLine(Charset.forName("UTF-8"), {
25 | var line = it
26 | line = line.replace("output.outputFile.parent, \"MyPolarPack",
27 | "output.outputFile.parent, \"${Main.USER_APPNAME}")
28 | line = processLineProperty("applicationId", line, "\"${Main.USER_PACKAGE}\"")
29 | line = processLineProperty("versionName", line, "\"${Main.USER_VERSION_NAME}\"")
30 | line = processLineProperty("versionCode", line, Main.USER_VERSION_CODE)
31 | lines.add(line)
32 | })
33 | } catch (e: Exception) {
34 | MainBase.LOG("[ERROR]: Failed to migrate a Gradle file: ${e.message}")
35 | uiCallback?.onErrorOccurred("Failed to migrate Gradle file: ${e.message}")
36 | e.printStackTrace()
37 | return false
38 | }
39 |
40 | mProject.delete()
41 | var os: OutputStream? = null
42 | var writer: BufferedWriter? = null
43 |
44 | try {
45 | os = FileOutputStream(mProject)
46 | writer = BufferedWriter(OutputStreamWriter(os))
47 |
48 | for (i in lines.indices) {
49 | if (i > 0) writer.newLine()
50 | writer.write(lines[i])
51 | }
52 | } catch (e: Exception) {
53 | MainBase.LOG("[ERROR]: Failed to migrate a Gradle file: ${e.message}")
54 | uiCallback?.onErrorOccurred("Failed to migrate Gradle file: ${e.message}")
55 | e.printStackTrace()
56 | return false
57 | } finally {
58 | Util.closeQuietely(writer)
59 | Util.closeQuietely(os)
60 | }
61 |
62 | val cleanedPath = MainBase.cleanupPath(mProject.absolutePath)
63 | MainBase.LOG("[INFO]: Migrated Gradle file $cleanedPath")
64 | uiCallback?.onStatusUpdate("Migrated Gradle file: $cleanedPath")
65 | return true
66 | }
67 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/xml/XmlScanner.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.xml
2 |
3 | /**
4 | * @author Aidan Follestad (afollestad)
5 | */
6 | class XmlScanner(private val mXml: StringBuilder) {
7 |
8 | private var mIndex = 0
9 | private var mTagName: String = ""
10 | private var mTagValue: String = ""
11 | private var mTagStart: Int = 0
12 | private var mTagEnd: Int = 0
13 | private var mValueStart: Int = 0
14 | private var mValueEnd: Int = 0
15 | private var mReachedEnd = false
16 |
17 | fun tagName(): String {
18 | return mTagName
19 | }
20 |
21 | fun tagValue(): String {
22 | return mTagValue
23 | }
24 |
25 | fun reachedEnd(): Boolean {
26 | return mReachedEnd
27 | }
28 |
29 | fun currentTag(): String {
30 | return mXml.substring(mTagStart, mTagEnd)
31 | }
32 |
33 | fun nextTag(): String? {
34 | if (mReachedEnd) return null
35 | val next: Int
36 | val firstSpace: Int
37 | try {
38 | mTagStart = mXml.indexOf("<", mIndex)
39 | if (mTagStart < 0) {
40 | // No more tags in the file
41 | mReachedEnd = true
42 | return null
43 | } else if (mXml[mTagStart + 1] == '?') {
44 | // Skip header
45 | mIndex = mXml.indexOf("?>", mTagStart + 1) + 2
46 | return nextTag()
47 | } else if (mXml[mTagStart + 1] == '!') {
48 | // Skip comments
49 | mIndex = mXml.indexOf("-->", mTagStart + 1) + 3
50 | return nextTag()
51 | }
52 |
53 | next = mXml.indexOf(">", mTagStart)
54 | firstSpace = mXml.indexOf(" ", mTagStart)
55 | if (firstSpace == -1) {
56 | mReachedEnd = true
57 | return null
58 | } else if (firstSpace > next) {
59 | // Skip elements with no attributes
60 | mIndex = firstSpace + 1
61 | return nextTag()
62 | } else if (!mXml.substring(mTagStart, next).contains(" name=")) {
63 | // Skip elements with no name attribute
64 | mIndex = next + 1
65 | return nextTag()
66 | }
67 |
68 | mTagName = mXml.substring(mTagStart + 1, firstSpace)
69 | val endFindStr = "$mTagName>"
70 | mTagEnd = mXml.indexOf(endFindStr, next + 1)
71 | if (mTagEnd < 0) {
72 | // Didn't find an end to this tag, skip it
73 | mIndex = mTagEnd + 1
74 | return nextTag()
75 | }
76 | mValueStart = next + 1
77 | mValueEnd = mTagEnd
78 | mTagValue = mXml.substring(mValueStart, mValueEnd)
79 | mTagEnd += endFindStr.length
80 |
81 | val tag = mXml.substring(mTagStart, mTagEnd)
82 | mIndex = mTagEnd
83 | return tag
84 | } catch (t: Throwable) {
85 | throw RuntimeException(t)
86 | }
87 |
88 | }
89 |
90 | // public void reset() {
91 | // mIndex = 0;
92 | // mReachedEnd = false;
93 | // }
94 |
95 | fun setElementValue(value: String) {
96 | val endFindStr = "$mTagName>"
97 | mTagValue = value
98 | mXml.replace(mValueStart, mValueEnd, value)
99 | mValueEnd = mValueStart + mTagValue.length
100 | mTagEnd = mValueEnd + endFindStr.length
101 | mIndex = mTagEnd
102 | }
103 |
104 | override fun toString(): String {
105 | return mXml.substring(mIndex)
106 | }
107 | }
--------------------------------------------------------------------------------
/src/main/resources/applicationUI.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
32 |
33 |
41 |
42 |
43 |
44 |
45 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/AttributeExtractor.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool
2 |
3 | import com.afollestad.polarupgradetool.jfx.UICallback
4 | import java.io.File
5 | import java.nio.charset.Charset
6 | import java.util.*
7 | import java.util.regex.Pattern
8 |
9 | /**
10 | * @author Aidan Follestad (afollestad)
11 | */
12 | class AttributeExtractor(private val mFile: File, private val mAttributeNames: Array, private val mMode: Int, private val uiCallback: UICallback?) {
13 |
14 | fun find(): HashMap? {
15 | if (!mFile.exists()) {
16 | MainBase.LOG("[ERROR]: File ${mFile.absolutePath} does not exist.")
17 | uiCallback?.onErrorOccurred("File does not exist: ${mFile.absolutePath}.")
18 | return null
19 | }
20 |
21 | var patterns: Array? = null
22 | if (mMode == MODE_XML) {
23 | patterns = Array(mAttributeNames.size, {
24 | it ->
25 | Pattern.compile(XML_REGEX.format(mAttributeNames[it]))
26 | })
27 | }
28 |
29 | val results = HashMap(mAttributeNames.size)
30 |
31 | try {
32 | mFile.forEachLine(Charset.forName("UTF-8"), {
33 | if (patterns != null) {
34 | // XML
35 | for (pattern in patterns!!) {
36 | val matcher = pattern.matcher(it)
37 | if (matcher.find()) {
38 | var result = it.substring(matcher.start(), matcher.end())
39 | val name = result.substring(0, result.indexOf('='))
40 | result = result.substring(result.indexOf('=') + 1, result.length)
41 | if (result.startsWith("\"") && result.endsWith("\"") || result.startsWith("'") && result.endsWith("'")) {
42 | result = result.substring(1, result.length - 1)
43 | }
44 | results.put(name, result)
45 | break
46 | }
47 | }
48 | } else {
49 | // Gradle
50 | for (attr in mAttributeNames) {
51 | val start = it.indexOf(attr + " ")
52 | if (start == -1) continue
53 | var result = it.substring(start, it.length).trim { it <= ' ' }
54 | val name = result.substring(0, result.indexOf(' '))
55 | result = result.substring(result.indexOf(' ') + 1)
56 | if (result.startsWith("\"") && result.endsWith("\"") || result.startsWith("'") && result.endsWith("'")) {
57 | result = result.substring(1, result.length - 1)
58 | }
59 | results.put(name, result)
60 | }
61 | }
62 | })
63 | } catch (e: Exception) {
64 | MainBase.LOG("[ERROR] Failed to read ${mFile.absolutePath}: ${e.message}")
65 | uiCallback?.onErrorOccurred("Failed to read ${mFile.absolutePath}: ${e.message}")
66 | e.printStackTrace()
67 | return null
68 | }
69 | return results
70 | }
71 |
72 | companion object {
73 |
74 | private val XML_REGEX = "%s=[\"']?((?:.(?![\"']?\\s+(?:\\S+)=|[>\"']))+.)[\"']?"
75 |
76 | val MODE_XML = 1
77 | val MODE_GRADLE = 2
78 |
79 | fun getAttributeValue(name: String, tag: String): String? {
80 | val pattern = Pattern.compile(XML_REGEX.format(name))
81 | val matcher = pattern.matcher(tag)
82 | if (matcher.find()) {
83 | var result = tag.substring(matcher.start(), matcher.end())
84 | result = result.substring(result.indexOf('=') + 1, result.length)
85 | if (result.startsWith("\"") && result.endsWith("\""))
86 | result = result.substring(1, result.length - 1)
87 | return result
88 | }
89 | return null
90 | }
91 |
92 | fun getElementValue(tag: String): String? {
93 | try {
94 | val start = tag.indexOf('>')
95 | if (start < 0) return null
96 | val end = tag.lastIndexOf("")
97 | if (end < 0) return null
98 | return tag.substring(start + 1, end)
99 | } catch (t: Throwable) {
100 | return null
101 | }
102 | }
103 | }
104 | }
--------------------------------------------------------------------------------
/dependency-reduced-pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | com.afollestad
5 | polarupgradetool
6 | 1.0.10
7 |
8 |
9 |
10 | ${basedir}/src/main/resources
11 |
12 | *.fxml
13 | *.png
14 |
15 |
16 |
17 |
18 |
19 | maven-dependency-plugin
20 | ${maven-dependencies-plugin.version}
21 |
22 |
23 | copy-dependencies
24 | prepare-package
25 |
26 | copy-dependencies
27 |
28 |
29 | ${project.build.directory}/lib
30 | true
31 | false
32 | false
33 |
34 |
35 |
36 |
37 |
38 | maven-compiler-plugin
39 | ${maven-compiler-plugin.version}
40 |
41 | ${java.compile.version}
42 | ${java.compile.version}
43 | ${java.compile.version}
44 |
45 |
46 |
47 | maven-jar-plugin
48 | ${maven-jar-plugin.version}
49 |
50 |
51 |
52 | true
53 | lib/
54 | com.afollestad.polarupgradetool.jfx.UpgradeTool
55 |
56 |
57 | ${put.version}
58 |
59 |
60 |
61 |
62 |
63 | maven-assembly-plugin
64 |
65 |
66 | make-my-jar-with-dependencies
67 | package
68 |
69 | single
70 |
71 |
72 |
73 |
74 |
75 |
76 | true
77 | com.afollestad.polarupgradetool.jfx.UpgradeTool
78 |
79 |
80 |
81 | jar-with-dependencies
82 |
83 |
84 |
85 |
86 | maven-shade-plugin
87 | ${maven-shade-plugin.version}
88 |
89 |
90 | package
91 |
92 | shade
93 |
94 |
95 | false
96 | true
97 | false
98 | true
99 |
100 |
101 |
102 |
103 |
104 | com.zenjava
105 | javafx-maven-plugin
106 | 8.1.4
107 |
108 | com.afollestad.polarupgradetool.jfx.UpgradeTool
109 |
110 |
111 |
112 |
113 |
114 |
115 | com.oracle
116 | javafx
117 | 2.2
118 | system
119 | ${project.basedir}/src/main/lib/jfxrt.jar
120 |
121 |
122 |
123 | 1.8
124 | 3.0
125 | 2.6
126 | 2.4.1
127 | 2.10
128 | ${version}
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/utils/ManifestUtils.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.utils
2 |
3 | import org.apache.maven.model.Model
4 | import org.apache.maven.model.io.xpp3.MavenXpp3Reader
5 | import java.io.BufferedReader
6 | import java.io.File
7 | import java.io.IOException
8 | import java.io.InputStreamReader
9 | import java.net.MalformedURLException
10 | import java.net.URL
11 | import java.text.CharacterIterator
12 | import java.text.StringCharacterIterator
13 | import java.util.jar.JarFile
14 |
15 | /**
16 | * Project : polarupgradetool
17 | * Author : pddstudio
18 | * Year : 2016
19 | */
20 | object ManifestUtils {
21 |
22 | private val GITHUB_POM_URL = "https://raw.githubusercontent.com/afollestad/polar-dashboard-upgrade-tool/master/pom.xml"
23 | private val MANIFEST_PUT_VERSION = "PUT-Version"
24 | private val VERSION_UNKNOWN = "???"
25 |
26 | //e.printStackTrace();
27 | val remoteApplicationModel: Model?
28 | get() {
29 | try {
30 | val mavenXpp3Reader = MavenXpp3Reader()
31 | val mavenUrl = URL(GITHUB_POM_URL)
32 | val inputStreamReader = InputStreamReader(mavenUrl.openStream())
33 | val bufferedReader = BufferedReader(inputStreamReader)
34 | val pom = mavenXpp3Reader.read(bufferedReader)
35 | bufferedReader.close()
36 | return pom
37 | } catch (e: Exception) {
38 | return null
39 | }
40 |
41 | }
42 |
43 | fun getApplicationVersion(className: Class<*>): String {
44 | val jarName: File?
45 | try {
46 |
47 | jarName = getClassSource(className)
48 | if (jarName == null) return VERSION_UNKNOWN
49 |
50 | val jarFile = JarFile(jarName)
51 | val attributes = jarFile.manifest.mainAttributes ?: return VERSION_UNKNOWN
52 |
53 | for (key in attributes.keys) {
54 | if (key.toString() == MANIFEST_PUT_VERSION) return attributes[key].toString()
55 | }
56 |
57 | } catch (io: IOException) {
58 | io.printStackTrace()
59 | }
60 |
61 | return VERSION_UNKNOWN
62 | }
63 |
64 | fun getClassSource(className: Class<*>): File? {
65 | val classResource = className.name.replace(".", "/") + ".class"
66 | var classLoader: ClassLoader? = className.classLoader
67 | if (classLoader == null) classLoader = ManifestUtils::class.java.classLoader
68 | val url: URL?
69 | if (classLoader == null) {
70 | url = ClassLoader.getSystemResource(classResource)
71 | } else {
72 | url = classLoader.getResource(classResource)
73 | }
74 | if (url != null) {
75 | val urlString = url.toString()
76 | val split: Int
77 | val jarName: String
78 | if (urlString.startsWith("jar:file:")) {
79 | split = urlString.indexOf("!")
80 | jarName = urlString.substring(4, split)
81 | return File(fromUri(jarName))
82 | } else if (urlString.startsWith("file:")) {
83 | split = urlString.indexOf(classResource)
84 | jarName = urlString.substring(0, split)
85 | return File(fromUri(jarName))
86 | }
87 | }
88 | return null
89 | }
90 |
91 | private fun fromUri(uri: String): String {
92 | var newUri = uri
93 | var url: URL? = null
94 | try {
95 | url = URL(newUri)
96 | } catch (emYouEarlEx: MalformedURLException) {
97 | // Ignore malformed exception
98 | }
99 |
100 | if (url == null || "file" != url.protocol) {
101 | throw IllegalArgumentException("Can only handle valid file: URIs")
102 | }
103 | val buf = StringBuilder(url.host)
104 | if (buf.length > 0) {
105 | buf.insert(0, File.separatorChar).insert(0, File.separatorChar)
106 | }
107 | val file = url.file
108 | val queryPos = file.indexOf('?')
109 | buf.append(if (queryPos < 0) file else file.substring(0, queryPos))
110 |
111 | newUri = buf.toString().replace('/', File.separatorChar)
112 |
113 | if (File.pathSeparatorChar == ';' && newUri.startsWith("\\") && newUri.length > 2
114 | && Character.isLetter(newUri[1]) && newUri.lastIndexOf(':') > -1) {
115 | newUri = newUri.substring(1)
116 | }
117 | return decodeUri(newUri)
118 | }
119 |
120 | private fun decodeUri(uri: String): String {
121 | if (uri.indexOf('%') == -1) {
122 | return uri
123 | }
124 | val sb = StringBuilder()
125 | val iter = StringCharacterIterator(uri)
126 | var c = iter.first()
127 | while (c != CharacterIterator.DONE) {
128 | if (c == '%') {
129 | val c1 = iter.next()
130 | if (c1 != CharacterIterator.DONE) {
131 | val i1 = Character.digit(c1, 16)
132 | val c2 = iter.next()
133 | if (c2 != CharacterIterator.DONE) {
134 | val i2 = Character.digit(c2, 16)
135 | sb.append(((i1 shl 4) + i2).toChar())
136 | }
137 | }
138 | } else {
139 | sb.append(c)
140 | }
141 | c = iter.next()
142 | }
143 | return sb.toString()
144 | }
145 | }
--------------------------------------------------------------------------------
/src/main/resources/aboutUI.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/xml/XmlMigrator.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.xml
2 |
3 | import com.afollestad.polarupgradetool.AttributeExtractor
4 | import com.afollestad.polarupgradetool.Main
5 | import com.afollestad.polarupgradetool.MainBase
6 | import com.afollestad.polarupgradetool.jfx.UICallback
7 | import java.io.File
8 | import java.nio.charset.Charset
9 | import java.nio.file.Files
10 | import java.nio.file.Paths
11 | import java.util.*
12 |
13 | /**
14 | * @author Aidan Follestad (afollestad)
15 | */
16 | class XmlMigrator(private val mProject: File, private val mLatest: File, private val uiCallback: UICallback?) {
17 |
18 | @SuppressWarnings("ResultOfMethodCallIgnored")
19 | fun process(): Boolean {
20 | val cleanedProjectPath = MainBase.cleanupPath(mProject.absolutePath)
21 | val cleanedLatestPath = MainBase.cleanupPath(mLatest.absolutePath)
22 |
23 | if (!mProject.exists()) {
24 | MainBase.LOG("[ERROR]: $cleanedProjectPath} doesn't exist.")
25 | uiCallback?.onErrorOccurred("$cleanedProjectPath doesn't exist.")
26 | return false
27 | } else if (!mLatest.exists()) {
28 | MainBase.LOG("[ERROR]: $cleanedLatestPath doesn't exist.")
29 | uiCallback?.onErrorOccurred("$cleanedLatestPath doesn't exist.")
30 | return false
31 | }
32 |
33 | val mSourceValues = HashMap()
34 |
35 | // Read the project (local) file to pull out the user's current configuration
36 | try {
37 | val fileRaw = Files.readAllBytes(Paths.get(mProject.absolutePath))
38 | val fileContent = StringBuilder(String(fileRaw, Charset.forName("UTF-8")))
39 | val scanner = XmlScanner(fileContent)
40 |
41 | while (!scanner.reachedEnd()) {
42 | val tag = scanner.nextTag() ?: continue
43 | val attributeName = AttributeExtractor.getAttributeValue("name", tag)
44 | val tagValue = scanner.tagValue()
45 | mSourceValues.put(attributeName!!, tagValue)
46 | }
47 | } catch (e: Exception) {
48 | MainBase.LOG("[ERROR]: Failed to process $cleanedProjectPath for XML migration: ${e.message}")
49 | uiCallback?.onErrorOccurred("Failed to process $cleanedProjectPath for XML migration: ${e.message}")
50 | e.printStackTrace()
51 | return false
52 | }
53 |
54 | if (mProject.name == "dev_customization.xml") {
55 | // If project defaults are used in project file, set them to empty/null
56 | if (!mSourceValues.containsKey("wallpapers_json_url")) {
57 | mSourceValues.put("wallpapers_json_url", "")
58 | }
59 | if (!mSourceValues.containsKey("icon_request_email") || mSourceValues["icon_request_email"] == "fake-email@fake-website.com") {
60 | mSourceValues.put("icon_request_email", "")
61 | }
62 | if (!mSourceValues.containsKey("donate_license_key")) {
63 | mSourceValues.put("donate_license_key", "")
64 | }
65 | if (!mSourceValues.containsKey("feedback_email") || mSourceValues["feedback_email"] == "fake-email@fake-website.com") {
66 | mSourceValues.put("feedback_email", mSourceValues["icon_request_email"]!!)
67 | }
68 | if (!mSourceValues.containsKey("homepage_landing_icon")) {
69 | mSourceValues.put("homepage_landing_icon", "@mipmap/ic_launcher")
70 | }
71 | }
72 | if (mProject.name == "dev_zooper.xml") {
73 | if (!mSourceValues.containsKey("enable_zooper_page")) {
74 | val assetsFolder = File(MainBase.CURRENT_DIR, Main.ASSETS_FOLDER_PATH)
75 | val templatesFolder = File(assetsFolder, "templates")
76 | val list = templatesFolder.list()
77 | mSourceValues.put("enable_zooper_page", if (list != null && list.size > 0) "true" else "false")
78 | }
79 | }
80 |
81 | // Put original project configuration back where possible, leaving new configuration added
82 | val newFileContent: StringBuilder
83 | try {
84 | val fileRaw = Files.readAllBytes(Paths.get(mLatest.absolutePath))
85 | newFileContent = StringBuilder(String(fileRaw, Charset.forName("UTF-8")))
86 | val scanner = XmlScanner(newFileContent)
87 |
88 | while (!scanner.reachedEnd()) {
89 | val tag = scanner.nextTag() ?: continue
90 | val attributeName = AttributeExtractor.getAttributeValue("name", tag) ?: continue
91 | if (mSourceValues.containsKey(attributeName)) {
92 | scanner.setElementValue(mSourceValues[attributeName]!!)
93 | } else if (attributeName == "about_buttons_names" || attributeName == "about_buttons_links") {
94 | if (!Main.OLD_ABOUT_BUTTON1_TEXT.isEmpty() && !Main.OLD_ABOUT_BUTTON2_TEXT.isEmpty() ||
95 | !Main.OLD_ABOUT_BUTTON1_LINK.isEmpty() && !Main.OLD_ABOUT_BUTTON2_LINK.isEmpty()) {
96 | val value = StringBuilder(scanner.tagValue())
97 | val start = value.indexOf("- ") + "
- ".length
98 | val end = value.indexOf("
", start)
99 | if (attributeName == "about_buttons_names" && !Main.OLD_ABOUT_BUTTON1_TEXT.isEmpty()) {
100 | value.replace(start, end, "%s|%s".format(Main.OLD_ABOUT_BUTTON1_TEXT, Main.OLD_ABOUT_BUTTON2_TEXT))
101 | } else if (attributeName == "about_buttons_links" && !Main.OLD_ABOUT_BUTTON1_LINK.isEmpty()) {
102 | value.replace(start, end, "%s|%s".format(Main.OLD_ABOUT_BUTTON1_LINK, Main.OLD_ABOUT_BUTTON2_LINK))
103 | }
104 | scanner.setElementValue(value.toString())
105 | }
106 | }
107 | }
108 | } catch (e: Exception) {
109 | MainBase.LOG("[ERROR]: Failed to process $cleanedProjectPath for XML migration: ${e.message}")
110 | uiCallback?.onErrorOccurred("Failed to process $cleanedProjectPath for XML migration: ${e.message}")
111 | e.printStackTrace()
112 | return false
113 | }
114 |
115 | // Write the latest (remote) file's changed contents to the project (local) file
116 | try {
117 | mProject.delete()
118 | mProject.writeBytes(newFileContent.toString().toByteArray(Charset.forName("UTF-8")))
119 | } catch (e: Exception) {
120 | e.printStackTrace()
121 | MainBase.LOG("[ERROR]: Failed to write to $cleanedProjectPath: ${e.message}")
122 | uiCallback?.onErrorOccurred("Failed to write to $cleanedProjectPath: ${e.message}")
123 | e.printStackTrace()
124 | return false
125 | }
126 |
127 | MainBase.LOG("[MIGRATE]: $cleanedProjectPath")
128 | uiCallback?.onStatusUpdate("Migrated XML resource file: $cleanedProjectPath")
129 | return true
130 | }
131 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/MainBase.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool;
2 |
3 | import com.afollestad.polarupgradetool.jfx.UICallback
4 | import com.afollestad.polarupgradetool.utils.FileUtil
5 | import com.afollestad.polarupgradetool.utils.UnzipUtil
6 | import com.afollestad.polarupgradetool.utils.Util
7 | import java.io.File
8 | import java.io.FileOutputStream
9 | import java.io.InputStream
10 | import java.net.URL
11 |
12 | /**
13 | * @author Aidan Follestad (afollestad)
14 | */
15 | open class MainBase {
16 | companion object {
17 |
18 | private val ARCHIVE_URL = "https://github.com/afollestad/polar-dashboard/archive/master.zip"
19 | private val ARCHIVE_ROOT = File.separator + "polar-dashboard-master"
20 |
21 | val BUFFER_SIZE = 2048
22 | var EXTRACTED_ZIP_ROOT: File? = null
23 | var CURRENT_DIR: File? = null
24 |
25 | fun cleanupPath(path: String): String {
26 | var from = path
27 | if (from.startsWith(CURRENT_DIR!!.absolutePath)) {
28 | from = from.substring(CURRENT_DIR!!.absolutePath.length)
29 | } else if (from.startsWith(EXTRACTED_ZIP_ROOT!!.absolutePath)) {
30 | from = from.substring(EXTRACTED_ZIP_ROOT!!.absolutePath.length)
31 | }
32 | return from
33 | }
34 |
35 | public fun LOG(msg: String) {
36 | println(msg)
37 | }
38 |
39 | fun PROGRESS(label: String?, read: Long, total: Long): String {
40 | val percent = Math.ceil(read.toDouble() / total.toDouble() * 100.0).toInt()
41 | val sb = StringBuilder(13)
42 | sb.append('\r')
43 | if (label != null) {
44 | sb.append(label)
45 | sb.append(" ")
46 | }
47 | sb.append('[')
48 | val numOfEqual = percent / 10
49 | val numOfSpace = 10 - numOfEqual
50 | for (i in 0..numOfEqual - 1) sb.append('=')
51 | for (i in 0..numOfSpace - 1) sb.append(' ')
52 | sb.append("]")
53 | sb.append(" ")
54 | sb.append(Util.round(percent.toFloat()))
55 | sb.append("% ")
56 | sb.append(Util.readableFileSizeMB(read))
57 | sb.append('/')
58 | sb.append(Util.readableFileSizeMB(total))
59 | print(sb.toString())
60 | return "%s/%s (%s%%)".format(Util.readableFileSizeMB(read), Util.readableFileSizeMB(total), Util.round(percent.toFloat()))
61 | }
62 |
63 | var TRIES = 0
64 |
65 | @SuppressWarnings("ResultOfMethodCallIgnored")
66 | fun downloadArchive(uiCallback: UICallback): Boolean {
67 | var `is`: InputStream? = null
68 | var os: FileOutputStream? = null
69 |
70 | if (TRIES == 0) {
71 | LOG("[INFO]: Contacting GitHub...")
72 | uiCallback.onStatusUpdate("Contacting GitHub...")
73 | }
74 |
75 | try {
76 | val url = URL(ARCHIVE_URL)
77 | val conn = url.openConnection()
78 | `is` = conn.inputStream
79 |
80 | val contentLength: Long
81 | try {
82 | val contentLengthStr = conn.getHeaderField("Content-Length")
83 | if (contentLengthStr == null || contentLengthStr.trim { it <= ' ' }.isEmpty()) {
84 | if (TRIES > 1) {
85 | LOG("[ERROR]: No Content-Length header was returned by GitHub. Try running this app again.")
86 | uiCallback.onErrorOccurred("GitHub did not report a Content-Length, please try again.")
87 | return false
88 | }
89 | TRIES++
90 | Thread.sleep(2000)
91 | return downloadArchive(uiCallback)
92 | }
93 | contentLength = java.lang.Long.parseLong(contentLengthStr)
94 | } catch (e: Throwable) {
95 | e.printStackTrace()
96 | LOG("[ERROR]: Failed to get the size of Polar's latest code archive. Please try running this app again.")
97 | uiCallback.onArchiveDownloadFailed("Failed to get the size of Polar's latest code archive. Please try running this app again.")
98 | return false
99 | }
100 |
101 | val destZip = File(CURRENT_DIR, "PolarLatest.zip")
102 | if (destZip.exists()) destZip.delete()
103 | os = FileOutputStream(destZip)
104 |
105 | val buffer = ByteArray(BUFFER_SIZE)
106 | var read: Int
107 | var totalRead = 0
108 |
109 | LOG("[INFO]: Downloading a ZIP of Polar's latest code (${FileUtil.readableFileSize(contentLength)})...")
110 | uiCallback.onArchiveDownloadStarted(FileUtil.readableFileSize(contentLength))
111 |
112 | while (true) {
113 | read = `is`!!.read(buffer);
114 | if (read == -1) break;
115 | os.write(buffer, 0, read)
116 | totalRead += read
117 | val progressStr = PROGRESS(null, totalRead.toLong(), contentLength)
118 | uiCallback.onArchiveDownloadProgress(progressStr)
119 | }
120 |
121 | PROGRESS(null, contentLength, contentLength)
122 | println()
123 | LOG("[INFO]: Download complete!")
124 | uiCallback.onArchiveDownloadSuccess()
125 | os.flush()
126 |
127 | Util.closeQuietely(`is`)
128 | Util.closeQuietely(os)
129 |
130 | EXTRACTED_ZIP_ROOT = File(CURRENT_DIR, "PolarLatest")
131 | val destZipPath = destZip.absolutePath
132 | val extractedPath = EXTRACTED_ZIP_ROOT!!.absolutePath
133 | if (EXTRACTED_ZIP_ROOT!!.exists()) {
134 | val removedCount = FileUtil.wipe(EXTRACTED_ZIP_ROOT!!)
135 | LOG("[INFO]: Removed $removedCount files/folders from $extractedPath.")
136 | uiCallback.onStatusUpdate("Removed $removedCount files/folders from $extractedPath.");
137 | }
138 |
139 | LOG("[INFO]: Extracting ${cleanupPath(destZipPath)} to ${cleanupPath(extractedPath)}...")
140 | uiCallback.onStatusUpdate("Extracting ${cleanupPath(destZipPath)} to ${cleanupPath(extractedPath)}...")
141 | UnzipUtil.unzip(destZipPath, extractedPath)
142 | LOG("[INFO]: Extraction complete!\n")
143 | uiCallback.onStatusUpdate("Extraction complete!")
144 | destZip.delete()
145 | EXTRACTED_ZIP_ROOT = File(EXTRACTED_ZIP_ROOT, ARCHIVE_ROOT)
146 | } catch (e: Exception) {
147 | LOG("[ERROR]: An error occurred during download or extraction: ${e.message}\n")
148 | uiCallback.onErrorOccurred("An error occurred during download or extraction: ${e.message}")
149 | return false
150 | } finally {
151 | Util.closeQuietely(`is`)
152 | Util.closeQuietely(os)
153 | }
154 | return true
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/jfx/UpgradeTool.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.jfx
2 |
3 | import com.afollestad.polarupgradetool.utils.UpdateUtils
4 | import com.afollestad.polarupgradetool.utils.UrlUtils
5 | import javafx.application.Application
6 | import javafx.application.HostServices
7 | import javafx.application.Platform
8 | import javafx.geometry.Pos
9 | import javafx.scene.control.Alert
10 | import javafx.scene.control.ButtonType
11 | import javafx.scene.image.Image
12 | import javafx.stage.Stage
13 | import javafx.util.Duration
14 | import org.controlsfx.control.Notifications
15 |
16 | /**
17 | * Project : polar-dashboard-upgrade-tool
18 | * Author : pddstudio
19 | * Year : 2016
20 | */
21 | class UpgradeTool : Application(), UpdateUtils.UpdateCallback {
22 |
23 | private var silent = true
24 |
25 | @Throws(Exception::class)
26 | override fun start(stage: Stage) {
27 | instance = this
28 | hostService = hostServices
29 |
30 | stage.title = "Polar Dashboard Upgrade Tool"
31 | stage.isResizable = false
32 |
33 | val windowScene = WindowScene()
34 | val scene = windowScene.scene
35 |
36 | stage.icons.add(Image(javaClass.getResourceAsStream("/polar_upgrade_1024.png")))
37 | stage.scene = scene
38 | stage.show()
39 |
40 | updateCheck()
41 | }
42 |
43 | fun updateCheck() {
44 | UpdateUtils.checkForUpdate(this).execute()
45 | }
46 |
47 | override fun onUpdateCheckStarted() {
48 | }
49 |
50 | override fun onUpdateCheckFailed(errorMsg: String) {
51 | if (Platform.isFxApplicationThread()) {
52 | if (!silent) {
53 | val alert = Alert(Alert.AlertType.ERROR)
54 | with(alert) {
55 | title = "Polar Upgrade Tool: Error"
56 | headerText = "Unable to check for update!"
57 | contentText = "An error occurred while trying to resolve the latest version of Polar Upgrade Tool:\n\n$errorMsg\n\nPlease make sure you're connected to the internet and try again,\notherwise head over to the GitHub Repository."
58 | dialogPane.setPrefSize(550.0, 360.0)
59 | isResizable = false
60 | showAndWait()
61 | }
62 | }
63 | silent = false
64 | } else
65 | Platform.runLater { onUpdateCheckFailed(errorMsg) }
66 | }
67 |
68 | @Suppress("NAME_SHADOWING")
69 | override fun onUpdateCheckFinished(currentVersion: String, latestVersion: String) {
70 | var currentVersion = currentVersion
71 | var latestVersion = latestVersion
72 | if (currentVersion.endsWith("-SNAPSHOT"))
73 | currentVersion = currentVersion.substring(0, currentVersion.indexOf("-SNAPSHOT"))
74 | if (latestVersion.endsWith("-SNAPSHOT"))
75 | latestVersion = latestVersion.substring(0, latestVersion.indexOf("-SNAPSHOT"))
76 |
77 | val current = parseVersion(currentVersion)
78 | val latest = parseVersion(latestVersion)
79 |
80 | if (Platform.isFxApplicationThread()) {
81 | if (isNewer(latest, current)) {
82 | val alert = Alert(Alert.AlertType.INFORMATION)
83 | with(alert) {
84 | title = "Polar Upgrade Tool: Information"
85 | headerText = "Update available:\n" + latestVersion
86 | contentText = "A new version for Polar Upgrade Tool is available!\n\nCurrent Version: $currentVersion\nLatest Version: $latestVersion\n\nNote: It's always recommended to use the latest version."
87 | dialogPane.setPrefSize(500.0, 260.0)
88 | isResizable = false
89 |
90 | val okBtn = ButtonType("Update")
91 | val ignBtn = ButtonType("Skip")
92 |
93 | buttonTypes.removeAll(alert.buttonTypes)
94 | buttonTypes.addAll(ignBtn, okBtn)
95 |
96 | val result = alert.showAndWait()
97 | if (result.get() == okBtn) {
98 | UrlUtils.openReleasePage()
99 | Platform.exit()
100 | System.exit(0)
101 | }
102 | }
103 | } else if (!silent) {
104 | //show a notification to give visual feedback that the operation was successful
105 | Notifications.create().title("Everything is up to date").text("Current Version: $currentVersion\nLatest Version: $latestVersion").hideAfter(Duration.seconds(3.0)).position(Pos.TOP_RIGHT).showInformation()
106 | }
107 | silent = false
108 | } else {
109 | val fCurrentVersion = currentVersion
110 | val fLatestVersion = latestVersion
111 | Platform.runLater { onUpdateCheckFinished(fCurrentVersion, fLatestVersion) }
112 | }
113 | }
114 |
115 | companion object {
116 |
117 | val GITHUB_REPO = "https://github.com/afollestad/polar-dashboard-upgrade-tool"
118 |
119 | var hostService: HostServices? = null
120 | private set
121 | var instance: UpgradeTool? = null
122 | private set
123 |
124 | private fun parseVersion(version: String): IntArray {
125 | if (version == "???")
126 | return intArrayOf(1, 0, 0)
127 | try {
128 | val split = version.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
129 | val result = IntArray(split.size)
130 | for (i in split.indices)
131 | result[i] = Integer.parseInt(split[i])
132 | return result
133 | } catch (t: Throwable) {
134 | return intArrayOf(1, 0, 0)
135 | }
136 | }
137 |
138 | @Suppress("NAME_SHADOWING")
139 | private fun isNewer(latest: IntArray, current: IntArray): Boolean {
140 | var latest = latest
141 | var current = current
142 | if (latest.size != current.size) {
143 | if (latest.size > current.size) {
144 | val newCurrent = IntArray(latest.size)
145 | for (i in newCurrent.indices) {
146 | if (i < current.size)
147 | newCurrent[i] = current[i]
148 | else
149 | newCurrent[i] = 0
150 | }
151 | current = newCurrent
152 | }
153 | if (current.size > latest.size) {
154 | val newLatest = IntArray(current.size)
155 | for (i in newLatest.indices) {
156 | if (i < latest.size)
157 | newLatest[i] = latest[i]
158 | else
159 | newLatest[i] = 0
160 | }
161 | latest = newLatest
162 | }
163 | }
164 | var newer = false
165 | for (i in latest.indices) {
166 | if (latest[i] > current[i]) {
167 | newer = true
168 | break
169 | }
170 | }
171 | return newer
172 | }
173 |
174 | @JvmStatic fun main(args: Array) {
175 | Application.launch(UpgradeTool::class.java, *args)
176 | }
177 | }
178 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | 4.0.0
7 |
8 | com.afollestad
9 | polarupgradetool
10 | 1.0.10
11 |
12 |
13 |
14 | 1.0.0
15 | 2.10
16 | 2.6
17 | 2.4.1
18 | 3.0
19 |
20 | 1.8
21 |
22 | ${version}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | org.apache.maven.plugins
31 | maven-dependency-plugin
32 | ${maven-dependencies-plugin.version}
33 |
34 |
35 | copy-dependencies
36 | prepare-package
37 |
38 | copy-dependencies
39 |
40 |
41 | ${project.build.directory}/lib
42 | true
43 | false
44 | false
45 |
46 |
47 |
48 |
49 |
50 | org.apache.maven.plugins
51 | maven-compiler-plugin
52 | ${maven-compiler-plugin.version}
53 |
54 | ${java.compile.version}
55 | ${java.compile.version}
56 | ${java.compile.version}
57 |
58 |
59 |
60 | org.apache.maven.plugins
61 | maven-jar-plugin
62 | ${maven-jar-plugin.version}
63 |
64 |
65 |
66 | true
67 | lib/
68 | com.afollestad.polarupgradetool.jfx.UpgradeTool
69 |
70 |
71 | ${put.version}
72 |
73 |
74 |
75 |
76 |
77 | maven-assembly-plugin
78 |
79 |
80 |
81 | true
82 | com.afollestad.polarupgradetool.jfx.UpgradeTool
83 |
84 |
85 |
86 | jar-with-dependencies
87 |
88 |
89 |
90 |
91 | make-my-jar-with-dependencies
92 | package
93 |
94 | single
95 |
96 |
97 |
98 |
99 |
100 | org.apache.maven.plugins
101 | maven-shade-plugin
102 | ${maven-shade-plugin.version}
103 |
104 |
105 | package
106 |
107 | shade
108 |
109 |
110 | false
111 | true
112 | false
113 | true
114 |
115 |
116 |
117 |
118 |
119 | com.zenjava
120 | javafx-maven-plugin
121 | 8.1.4
122 |
123 | com.afollestad.polarupgradetool.jfx.UpgradeTool
124 |
125 |
126 |
127 | org.jetbrains.kotlin
128 | kotlin-maven-plugin
129 | ${kotlin.version}
130 |
131 |
132 | compile
133 | process-sources
134 |
135 | compile
136 |
137 |
138 |
139 | src/main/java
140 |
141 |
142 |
143 |
144 | test-compile
145 | process-test-sources
146 |
147 | test-compile
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | false
159 | ${basedir}/src/main/resources
160 |
161 | *.fxml
162 | *.png
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | com.oracle
172 | javafx
173 | 2.2
174 | ${project.basedir}/src/main/lib/jfxrt.jar
175 | system
176 |
177 |
178 | org.controlsfx
179 | controlsfx
180 | 8.40.10
181 |
182 |
183 | org.apache.maven
184 | maven-model
185 | 3.3.9
186 |
187 |
188 | org.jetbrains.kotlin
189 | kotlin-stdlib
190 | ${kotlin.version}
191 |
192 |
193 | org.jetbrains.kotlin
194 | kotlin-stdlib
195 | 1.0.0
196 |
197 |
198 | no.tornado
199 | fx
200 | 1.2
201 |
202 |
203 |
204 |
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/utils/FileUtil.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.utils
2 |
3 | import com.afollestad.polarupgradetool.Main
4 | import com.afollestad.polarupgradetool.MainBase
5 | import com.afollestad.polarupgradetool.jfx.UICallback
6 | import java.io.*
7 | import java.nio.charset.Charset
8 | import java.nio.file.Files
9 | import java.nio.file.Paths
10 | import java.nio.file.StandardOpenOption
11 | import java.util.*
12 |
13 | /**
14 | * @author Aidan Follestad (afollestad)
15 | */
16 | object FileUtil {
17 |
18 | fun readableFileSize(size: Long): String {
19 | val value: Double
20 | val unit: String
21 | if (size < 1000) {
22 | value = size.toDouble()
23 | unit = "B"
24 | } else if (size >= 1000 && size < 1000000) {
25 | value = size.toDouble() / 1000.toDouble()
26 | unit = "KB"
27 | } else if (size >= 1000000 && size < 1000000000) {
28 | value = size.toDouble() / 1000000.toDouble()
29 | unit = "MB"
30 | } else {
31 | value = size.toDouble() / 1000000000.toDouble()
32 | unit = "GB"
33 | }
34 | return "${Util.round(value)}$unit"
35 | }
36 |
37 | @SuppressWarnings("ResultOfMethodCallIgnored")
38 | fun checkResRename(oldName: String, expectedName: String, uiCallback: UICallback) {
39 | val valuesFolder = File(MainBase.CURRENT_DIR, Main.VALUES_FOLDER_PATH)
40 | val source = File(valuesFolder, oldName)
41 | if (source.exists()) {
42 | val dest = File(valuesFolder, expectedName)
43 | if (!dest.exists()) {
44 | val cleanedSource = MainBase.cleanupPath(source.absolutePath)
45 | val cleanedDest = MainBase.cleanupPath(dest.absolutePath)
46 | MainBase.LOG("[RENAME]: $cleanedSource -> $cleanedDest")
47 | uiCallback.onStatusUpdate("Renaming $cleanedSource -> $cleanedDest")
48 | if (!source.renameTo(dest)) {
49 | MainBase.LOG("[ERROR]: Unable to rename $cleanedSource")
50 | uiCallback.onErrorOccurred("Unable to rename: $cleanedSource")
51 | }
52 | } else {
53 | source.delete()
54 | }
55 | } else {
56 | val msg = "$oldName file wasn't found (in ${MainBase.cleanupPath(source.parent)}), assuming $expectedName is used already."
57 | MainBase.LOG("[INFO] " + msg)
58 | uiCallback.onStatusUpdate(msg)
59 | }
60 | }
61 |
62 | @SuppressWarnings("ResultOfMethodCallIgnored")
63 | fun wipe(dir: File): Int {
64 | var count = 1
65 | if (dir.isDirectory) {
66 | val contents = dir.listFiles()
67 | if (contents != null && contents.size > 0) {
68 | for (fi in contents)
69 | count += wipe(fi)
70 | }
71 | }
72 | dir.delete()
73 | return count
74 | }
75 |
76 | @Throws(Exception::class)
77 | private fun copyFileText(src: File, dst: File, interceptor: CopyInterceptor?) {
78 | var out: OutputStream? = null
79 | var writer: BufferedWriter? = null
80 | try {
81 | out = FileOutputStream(dst)
82 | writer = BufferedWriter(OutputStreamWriter(out))
83 |
84 | src.forEachLine(Charset.forName("UTF-8"), {
85 | val newLine = if (interceptor != null) interceptor.onCopyLine(src, it) else it;
86 | writer?.write(newLine)
87 | writer?.newLine()
88 | })
89 | } finally {
90 | Util.closeQuietely(writer)
91 | Util.closeQuietely(out)
92 | }
93 | }
94 |
95 | @Throws(Exception::class)
96 | private fun copyFileBinary(src: File, dst: File) {
97 | var out: OutputStream? = null
98 | try {
99 | out = FileOutputStream(dst)
100 | src.forEachBlock { bytes, size ->
101 | out?.write(bytes, 0, size)
102 | }
103 | } finally {
104 | Util.closeQuietely(out)
105 | }
106 | }
107 |
108 | @SuppressWarnings("ResultOfMethodCallIgnored")
109 | fun replaceInFile(file: File, find: String, replace: String, uiCallback: UICallback): Boolean {
110 | try {
111 | val path = Paths.get(file.absolutePath)
112 | var content = Files.readAllBytes(path)
113 | var contentStr = String(content, Charset.forName("UTF-8"))
114 | contentStr = contentStr.replace(find, replace)
115 | content = contentStr.toByteArray(Charset.forName("UTF-8"))
116 | file.delete()
117 | Files.write(path, content, StandardOpenOption.CREATE, StandardOpenOption.WRITE)
118 | } catch (t: Throwable) {
119 | t.printStackTrace()
120 | MainBase.LOG("[ERROR]: Failed to perform a find and replace in ${MainBase.cleanupPath(file.absolutePath)}: ${t.message}}")
121 | uiCallback.onErrorOccurred("Failed to perform a find and replace in ${MainBase.cleanupPath(file.absolutePath)}: ${t.message}}")
122 | return false
123 | }
124 |
125 | return true
126 | }
127 |
128 | // Checks for files in the project folder that no longer exist in the latest code
129 | @SuppressWarnings("ResultOfMethodCallIgnored")
130 | fun checkDiff(project: File, latest: File, importMode: Boolean, callback: UICallback, interceptor: (File) -> Boolean): Boolean {
131 | if (importMode) {
132 | if (project.isDirectory && interceptor(project))
133 | return true
134 | if (!project.exists() && latest.exists()) {
135 | MainBase.LOG("[ADD]: ${MainBase.cleanupPath(latest.absolutePath)} -> ${MainBase.cleanupPath(project.absolutePath)}...")
136 | val result = copyFolder(latest, project, object : CopyInterceptor {
137 | override fun onCopyLine(file: File, line: String): String {
138 | return line.replace("com.afollestad.polar", Main.USER_CODE_PACKAGE)
139 | }
140 |
141 | override fun loggingEnabled(): Boolean {
142 | return true
143 | }
144 |
145 | override fun skip(file: File): Boolean {
146 | return false
147 | }
148 | }, callback)
149 | if (!result) return false
150 | }
151 | if (latest.isDirectory) {
152 | val files = latest.list()
153 | var result = true
154 | for (file in files) {
155 | val srcFile = File(project, file)
156 | val destFile = File(latest, file)
157 | if (!checkDiff(srcFile, destFile, true, callback, interceptor)) {
158 | result = false
159 | break
160 | }
161 | }
162 | return result
163 | }
164 | return true
165 | } else {
166 | if (interceptor(project))
167 | return true
168 | if (project.exists() && !latest.exists()) {
169 | MainBase.LOG("[DELETE]: %${MainBase.cleanupPath(project.absolutePath)}")
170 | if (project.isDirectory) {
171 | wipe(project)
172 | } else {
173 | project.delete()
174 | }
175 | } else if (project.isDirectory) {
176 | val files = project.list()
177 | var result = true
178 | for (file in files) {
179 | val srcFile = File(project, file)
180 | val destFile = File(latest, file)
181 | if (!checkDiff(srcFile, destFile, false, callback, interceptor)) {
182 | result = false
183 | }
184 | }
185 | return result
186 | }
187 | return true
188 | }
189 | }
190 |
191 | @SuppressWarnings("ResultOfMethodCallIgnored")
192 | fun copyFolder(source: File, destination: File, interceptor: CopyInterceptor?, callback: UICallback?): Boolean {
193 | val cleanedSourcePath = MainBase.cleanupPath(source.absolutePath)
194 | val cleanedDestPath = MainBase.cleanupPath(destination.absolutePath)
195 |
196 | if (interceptor != null && interceptor.skip(source)) {
197 | if (interceptor.loggingEnabled())
198 | MainBase.LOG("[SKIP]: $cleanedSourcePath")
199 | return true
200 | }
201 |
202 | if (interceptor == null || interceptor.loggingEnabled())
203 | MainBase.LOG("[COPY]: $cleanedSourcePath -> $cleanedDestPath")
204 | if (source.isDirectory) {
205 | if (!destination.exists())
206 | destination.mkdirs()
207 | val files = source.list()
208 | for (file in files) {
209 | val srcFile = File(source, file)
210 | val destFile = File(destination, file)
211 | if (!copyFolder(srcFile, destFile, interceptor, callback))
212 | return false
213 | }
214 | return true
215 | } else {
216 | try {
217 | val name = source.name.toLowerCase(Locale.getDefault())
218 | if (name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".png")) {
219 | copyFileBinary(source, destination)
220 | } else {
221 | copyFileText(source, destination, interceptor)
222 | }
223 | } catch (e: Exception) {
224 | e.printStackTrace()
225 | MainBase.LOG("[ERROR]: An error occurred while copying $cleanedSourcePath: ${e.message}")
226 | callback?.onErrorOccurred("An error occurred while copying $cleanedSourcePath: ${e.message}")
227 | return false
228 | }
229 |
230 | return true
231 | }
232 | }
233 | }
234 |
235 | interface CopyInterceptor {
236 | fun skip(file: File): Boolean
237 |
238 | fun onCopyLine(file: File, line: String): String
239 |
240 | fun loggingEnabled(): Boolean
241 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/jfx/WindowScene.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool.jfx
2 |
3 | import com.afollestad.polarupgradetool.Main
4 | import com.afollestad.polarupgradetool.utils.SecurityUtil
5 | import com.afollestad.polarupgradetool.utils.UrlUtils
6 | import javafx.application.Platform
7 | import javafx.collections.FXCollections
8 | import javafx.collections.ObservableList
9 | import javafx.fxml.FXML
10 | import javafx.fxml.FXMLLoader
11 | import javafx.scene.Scene
12 | import javafx.scene.control.*
13 | import javafx.scene.layout.StackPane
14 | import javafx.scene.layout.VBox
15 | import javafx.scene.paint.Color
16 | import javafx.stage.DirectoryChooser
17 | import javafx.stage.Stage
18 | import org.controlsfx.control.MaskerPane
19 | import org.controlsfx.glyphfont.FontAwesome
20 | import org.controlsfx.glyphfont.GlyphFontRegistry
21 | import java.io.File
22 | import java.io.IOException
23 | import java.util.*
24 |
25 | /**
26 | * Project : polar-dashboard-upgrade-tool
27 | * Author : pddstudio
28 | * Year : 2016
29 | */
30 | class WindowScene {
31 |
32 | var scene: Scene
33 | private val windowSceneController: WindowSceneController
34 | private var updateBtn: Button? = null
35 | private var logMessages: ObservableList? = null
36 |
37 | init {
38 | windowSceneController = WindowSceneController()
39 | scene = Scene(windowSceneController)
40 | windowSceneController.setRootScene(scene)
41 | }
42 |
43 | private inner class WindowSceneController internal constructor() : StackPane(), UICallback {
44 |
45 | private var selectedFolder: File? = null
46 | private var interfaceUpdateThread: InterfaceUpdateThread? = null
47 | private var maskerPane: MaskerPane? = null
48 | //main menu bar and menu items
49 | private var menuBar: MenuBar? = null
50 | private var fileMenu: Menu? = null
51 | private val fontAwesome = GlyphFontRegistry.font("FontAwesome")
52 |
53 | @FXML lateinit var logMessages: ObservableList
54 |
55 | //ui elements
56 | @FXML lateinit var projectLocationTextField: TextField
57 | // @FXML lateinit var browseButton: Button
58 | @FXML lateinit var messageListView: ListView
59 | @FXML lateinit var updateBtn: Button
60 | @FXML lateinit var copyrightLabel: Hyperlink
61 | @FXML lateinit var mainPane: StackPane
62 | @FXML lateinit var boxPane: VBox
63 |
64 | init {
65 | try {
66 | val fxmlLoader = FXMLLoader(javaClass.getResource("/applicationUI.fxml"))
67 | fxmlLoader.setRoot(this)
68 | fxmlLoader.setController(this)
69 | fxmlLoader.load()
70 |
71 | maskerPane = MaskerPane()
72 | maskerPane!!.isVisible = false
73 |
74 | mainPane.children.addAll(maskerPane)
75 |
76 | createMenuBar()
77 |
78 | projectLocationTextField.isEditable = false
79 | logMessages = FXCollections.observableArrayList()
80 | messageListView.items = logMessages
81 | messageListView.isEditable = false
82 | updateBtn.isVisible = false
83 | updateBtn.setOnAction { event ->
84 | //Main.upgrade(selectedFolder.getAbsolutePath(), WindowSceneController.this);
85 | with(maskerPane!!) {
86 | text = "Updating " + if (Main.USER_APPNAME.isEmpty()) "Project" else Main.USER_APPNAME
87 | isVisible = true
88 | }
89 | updateBtn.isVisible = false
90 | interfaceUpdateThread = InterfaceUpdateThread(selectedFolder!!.absolutePath, this)
91 | interfaceUpdateThread!!.start()
92 | }
93 |
94 | this@WindowScene.updateBtn = updateBtn
95 | this@WindowScene.logMessages = logMessages
96 | copyrightLabel.text = "(c) ${Calendar.getInstance().get(Calendar.YEAR)} Polar Upgrade Tool"
97 | } catch (io: IOException) {
98 | io.printStackTrace()
99 | }
100 |
101 | }
102 |
103 | private fun createMenuBar() {
104 | //create the menuBar
105 | menuBar = MenuBar()
106 | //Create the menuItems
107 | fileMenu = Menu("Menu")
108 | menuBar!!.menus.addAll(fileMenu)
109 | val helpItem = MenuItem("Help / Usage", fontAwesome.create(FontAwesome.Glyph.QUESTION).color(Color.color(0.0, 0.0, 0.0, 0.87)))
110 | helpItem.setOnAction { event -> UrlUtils.openWikiPage() }
111 |
112 | val checkUpdateItem = MenuItem("Check for Update", fontAwesome.create(FontAwesome.Glyph.DOWNLOAD).color(Color.color(0.0, 0.0, 0.0, 0.87)))
113 | checkUpdateItem.setOnAction { event -> UpgradeTool.instance?.updateCheck() }
114 |
115 | val aboutItem = MenuItem("About", fontAwesome.create(FontAwesome.Glyph.INFO).color(Color.color(0.0, 0.0, 0.0, 0.87)))
116 | aboutItem.setOnAction { event ->
117 | val stage = Stage()
118 | stage.title = "About Polar Upgrade Tool"
119 | stage.isResizable = false
120 | val aboutScene = AboutScene()
121 | stage.scene = aboutScene.scene
122 | stage.show()
123 | }
124 |
125 | fileMenu!!.items.addAll(helpItem, checkUpdateItem, aboutItem)
126 | boxPane.children.add(0, menuBar)
127 | }
128 |
129 | fun setRootScene(scene: Scene) {
130 | this@WindowScene.scene = scene
131 | }
132 |
133 | @FXML
134 | protected fun openFolderChooserDialog() {
135 | val directoryChooser = DirectoryChooser()
136 | selectedFolder = directoryChooser.showDialog(scene.window)
137 | if (selectedFolder != null) {
138 | projectLocationTextField.text = selectedFolder!!.absolutePath
139 | if (SecurityUtil.checkIsPolarBased(selectedFolder!!.absolutePath)) {
140 | updateBtn.isVisible = true
141 | } else {
142 | showSecurityInfoDialog(selectedFolder!!.absolutePath)
143 | }
144 | }
145 | }
146 |
147 | @FXML
148 | protected fun onHyperlinkClicked() {
149 | UpgradeTool.hostService?.showDocument(UpgradeTool.GITHUB_REPO)
150 | }
151 |
152 | override fun onProjectDetected(applicationName: String, applicationPackage: String, applicationVersionName: String, applicationVersionCode: String) {
153 | if (Platform.isFxApplicationThread()) {
154 | logMessages.add("Found Project: $applicationName [$applicationPackage], Version Name: $applicationVersionName, Version Code: $applicationVersionCode")
155 | messageListView.scrollTo(logMessages.size - 1)
156 | maskerPane!!.text = "Updating " + Main.USER_APPNAME
157 | } else {
158 | Platform.runLater { onProjectDetected(applicationName, applicationPackage, applicationVersionName, applicationVersionCode) }
159 | }
160 | }
161 |
162 | override fun onErrorOccurred(errorMessage: String) {
163 | if (Platform.isFxApplicationThread()) {
164 | maskerPane!!.isVisible = false
165 | showErrorDialog(errorMessage)
166 | } else {
167 | Platform.runLater {
168 | maskerPane!!.isVisible = false
169 | showErrorDialog(errorMessage)
170 | }
171 | }
172 | }
173 |
174 | override fun onArchiveDownloadStarted(sizeStr: String) {
175 | if (Platform.isFxApplicationThread()) {
176 | onStatusUpdate("Downloading a ZIP of Polar's latest code (%s)...".format(sizeStr))
177 | } else {
178 | Platform.runLater { onArchiveDownloadStarted(sizeStr) }
179 | }
180 | }
181 |
182 | override fun onArchiveDownloadProgress(progressStr: String) {
183 | if (Platform.isFxApplicationThread()) {
184 | maskerPane!!.text = "Downloading latest source\n" + progressStr
185 | } else {
186 | Platform.runLater { onArchiveDownloadProgress(progressStr) }
187 | }
188 | }
189 |
190 | override fun onArchiveDownloadSuccess() {
191 | if (Platform.isFxApplicationThread()) {
192 | onStatusUpdate("Download complete!")
193 | maskerPane!!.text = "Migrating resources..."
194 | } else {
195 | Platform.runLater {
196 | onArchiveDownloadSuccess()
197 | maskerPane!!.text = "Migrating resources..."
198 | }
199 | }
200 | }
201 |
202 | override fun onArchiveDownloadFailed(errorMessage: String) {
203 | if (Platform.isFxApplicationThread()) {
204 | showErrorDialog(errorMessage)
205 | maskerPane!!.isVisible = false
206 | } else {
207 | Platform.runLater { onArchiveDownloadFailed(errorMessage) }
208 | }
209 | }
210 |
211 | override fun onStatusUpdate(statusMessage: String) {
212 | if (Platform.isFxApplicationThread()) {
213 | logMessages.add(statusMessage)
214 | messageListView.scrollTo(logMessages.size - 1)
215 | } else {
216 | Platform.runLater { onStatusUpdate(statusMessage) }
217 | }
218 | }
219 |
220 | override fun onUpdateSuccessful() {
221 | if (Platform.isFxApplicationThread()) {
222 | maskerPane!!.isVisible = false
223 | showUpdateSuccessDialog()
224 | } else {
225 | Platform.runLater {
226 | maskerPane!!.isVisible = false
227 | showUpdateSuccessDialog()
228 | }
229 | }
230 | }
231 | }
232 |
233 | private fun showErrorDialog(message: String) {
234 | val alert = Alert(Alert.AlertType.ERROR)
235 | alert.title = "Polar Upgrade Tool: Error"
236 | alert.headerText = "An error occurred!"
237 | alert.contentText = message
238 | alert.dialogPane.setPrefSize(550.0, 270.0)
239 | alert.isResizable = true
240 | alert.setOnHiding { event ->
241 | // Platform.exit();
242 | // System.exit(0);
243 | logMessages!!.clear()
244 | if (updateBtn != null)
245 | updateBtn!!.isVisible = true
246 | }
247 | val result = alert.showAndWait()
248 | if (result.isPresent && result.get() == ButtonType.OK) {
249 | // Platform.exit();
250 | // System.exit(0);
251 | logMessages!!.clear()
252 | if (updateBtn != null)
253 | updateBtn!!.isVisible = true
254 | }
255 | }
256 |
257 | private fun showUpdateSuccessDialog() {
258 | val alert = Alert(Alert.AlertType.INFORMATION)
259 | alert.title = "Polar Upgrade Tool: Info"
260 | alert.headerText = "Update successful!"
261 | alert.contentText = "${Main.USER_APPNAME} is now up to date! Your configuration has been restored.\n\n" +
262 | "Find any issues? Please report them on GitHub. You can undo changes made by this tool either " +
263 | "using the backup ZIP archive placed in your project directory, or by using the following Git " +
264 | "commands:\n\ngit add -A\ngit stash save\ngit stash drop"
265 | alert.dialogPane.setPrefSize(550.0, 360.0)
266 | alert.isResizable = true
267 | alert.showAndWait()
268 | updateBtn!!.isVisible = true
269 | }
270 |
271 | fun showSecurityInfoDialog(path: String) {
272 | val alert = Alert(Alert.AlertType.WARNING)
273 | alert.title = "Polar Upgrade Tool: Warning"
274 | alert.headerText = "WARNING: Unable to find Polar based Project!"
275 | alert.dialogPane.setPrefSize(550.0, 360.0)
276 | alert.contentText = "The project located at:\n\n$path\n\ndoesn't seem to be a project based on Polar.\nProceeding with the upgrade might destroy your project setup and build system.\nPlease make sure to backup your current data before continuing,\nyou proceed at your own risk!"
277 | alert.isResizable = false
278 |
279 | val confirmBtn = ButtonType("Got it, Continue anyway!", ButtonBar.ButtonData.OK_DONE)
280 | val cancelBtn = ButtonType("Abort Process", ButtonBar.ButtonData.CANCEL_CLOSE)
281 |
282 | alert.buttonTypes.removeAll(alert.buttonTypes)
283 | alert.buttonTypes.addAll(confirmBtn, cancelBtn)
284 |
285 | val result = alert.showAndWait()
286 | if (result.get() == confirmBtn) {
287 | updateBtn!!.isVisible = true
288 | } else {
289 | updateBtn!!.isVisible = false
290 | }
291 |
292 | }
293 | }
--------------------------------------------------------------------------------
/src/main/java/com/afollestad/polarupgradetool/Main.kt:
--------------------------------------------------------------------------------
1 | package com.afollestad.polarupgradetool;
2 |
3 | import com.afollestad.polarupgradetool.jfx.UICallback
4 | import com.afollestad.polarupgradetool.utils.CopyInterceptor
5 | import com.afollestad.polarupgradetool.utils.FileUtil
6 | import com.afollestad.polarupgradetool.utils.Util
7 | import com.afollestad.polarupgradetool.utils.ZipUtil
8 | import com.afollestad.polarupgradetool.xml.XmlElementExtractor
9 | import com.afollestad.polarupgradetool.xml.XmlMigrator
10 | import java.io.File
11 | import java.nio.charset.Charset
12 | import java.nio.file.Files
13 | import java.nio.file.Paths
14 | import java.util.*
15 |
16 | /**
17 | * @author Aidan Follestad (afollestad)
18 | */
19 | class Main : MainBase() {
20 |
21 | open class PackageCopyInterceptor : CopyInterceptor {
22 | override fun onCopyLine(file: File, line: String): String {
23 | try {
24 | return line.replace("com.afollestad.polar", USER_CODE_PACKAGE)
25 | } catch (t: Throwable) {
26 | t.printStackTrace()
27 | return line
28 | }
29 |
30 | }
31 |
32 | override fun skip(file: File): Boolean {
33 | return isBlacklisted(file)
34 | }
35 |
36 | override fun loggingEnabled(): Boolean {
37 | return true
38 | }
39 | }
40 |
41 | companion object {
42 |
43 | fun isBlacklisted(file: File): Boolean {
44 | if (file.isDirectory) {
45 | return file.name.startsWith("mipmap") ||
46 | file.name == "drawable-nodpi" ||
47 | file.name == "xml" ||
48 | file.name == ".gradle" ||
49 | file.name == ".idea" ||
50 | file.name == "build" ||
51 | file.name == ".DS_Store"
52 | } else {
53 | return file.name == "list_item_about_dev.xml" ||
54 | file.name.startsWith("dev_") && file.name.endsWith(".xml") ||
55 | file.name == "theme_config.xml" ||
56 | file.name == "strings.xml" ||
57 | file.name == "colors.xml" ||
58 | file.name == "appfilter.xml" ||
59 | file.name == "icon_pack.xml" ||
60 | file.parent != null && file.parent == "drawable-nodpi"
61 | }
62 | }
63 |
64 | var USER_PACKAGE: String = ""
65 | var USER_VERSION_NAME: String = ""
66 | var USER_VERSION_CODE: String = ""
67 | var USER_APPNAME: String = ""
68 | var USER_CODE_PACKAGE: String = ""
69 |
70 | var OLD_ABOUT_BUTTON1_TEXT: String = ""
71 | var OLD_ABOUT_BUTTON1_LINK: String = ""
72 | var OLD_ABOUT_BUTTON2_TEXT: String = ""
73 | var OLD_ABOUT_BUTTON2_LINK: String = ""
74 |
75 | private val LIBS_FOLDER = File.separator + "app" + File.separator + "libs"
76 | private val LICENSING_MODULE_ROOT = File.separator + "licensing"
77 | private val GRADLE_FILE_PATH = File.separator + "app" + File.separator + "build.gradle"
78 | private val MAIN_FOLDER = File.separator + "app" + File.separator + "src" + File.separator + "main"
79 | private val JAVA_FOLDER_PATH = MAIN_FOLDER + File.separator + "java"
80 | val ASSETS_FOLDER_PATH = MAIN_FOLDER + File.separator + "assets"
81 | private val RES_FOLDER_PATH = MAIN_FOLDER + File.separator + "res"
82 | val VALUES_FOLDER_PATH = MAIN_FOLDER + File.separator + "res" + File.separator + "values"
83 | private val MANIFEST_FILE_PATH = MAIN_FOLDER + File.separator + "AndroidManifest.xml"
84 |
85 | @SuppressWarnings("ResultOfMethodCallIgnored")
86 | fun upgrade(projectPath: String, uiCallback: UICallback) {
87 | //CURRENT_DIR = new File(System.getProperty("user.dir"));
88 | MainBase.CURRENT_DIR = File(projectPath)
89 | println("\n--------------------------------------\n" +
90 | "| Welcome to the Polar upgrade tool! |\n" +
91 | "--------------------------------------")
92 |
93 | // Use app/build.gradle and /res/values/strings.xml to load info about icon pack
94 | val gradleFile = File(MainBase.CURRENT_DIR, GRADLE_FILE_PATH)
95 | val gradleExtractor = AttributeExtractor(gradleFile,
96 | arrayOf("applicationId", "versionName", "versionCode"), AttributeExtractor.MODE_GRADLE, uiCallback)
97 | val stringsExtractor = XmlElementExtractor(File(MainBase.CURRENT_DIR,
98 | "%s%s%s%s%s".format(RES_FOLDER_PATH, File.separator, "values", File.separator, "strings.xml")),
99 | arrayOf("string"), arrayOf("app_name"), uiCallback)
100 | val gradleAttrs = gradleExtractor.find() ?: return
101 | val stringsAttrs = stringsExtractor.find() ?: return
102 |
103 | USER_APPNAME = stringsAttrs["app_name"] ?: "Unknown"
104 | USER_PACKAGE = gradleAttrs["applicationId"] ?: "Unknown"
105 | USER_VERSION_NAME = gradleAttrs["versionName"] ?: "Unknown"
106 | USER_VERSION_CODE = gradleAttrs["versionCode"] ?: "Unknown"
107 | MainBase.LOG("[DETECTED]: app_name = $USER_APPNAME, applicationId = $USER_PACKAGE, versionName = $USER_VERSION_NAME, versionCode = $USER_VERSION_CODE")
108 | uiCallback.onProjectDetected(USER_APPNAME, USER_PACKAGE, USER_VERSION_NAME, USER_VERSION_CODE)
109 |
110 | // Pull out package name used for files
111 | var source = File(MainBase.CURRENT_DIR, JAVA_FOLDER_PATH)
112 | USER_CODE_PACKAGE = Util.detectCodePackage(source)
113 | LOG("[INFO]: Code package = $USER_CODE_PACKAGE")
114 |
115 | var projectBackup = File(MainBase.CURRENT_DIR, "PolarLatest")
116 | if (projectBackup.exists()) FileUtil.wipe(projectBackup)
117 | projectBackup = File(MainBase.CURRENT_DIR, "${USER_APPNAME.replace(" ", "_")}-BACKUP.zip")
118 | if (projectBackup.exists()) projectBackup.delete()
119 |
120 | val cleanBackupPath = cleanupPath(projectBackup.absolutePath)
121 | LOG("[INFO]: Backing up your existing project to $cleanBackupPath...")
122 | uiCallback.onStatusUpdate("Backing up your existing project to $cleanBackupPath...")
123 | try {
124 | ZipUtil.writeZipFile(MainBase.CURRENT_DIR as File, projectBackup)
125 | } catch (e: Exception) {
126 | e.printStackTrace()
127 | MainBase.Companion.LOG("[ERROR]: Failed to make a backup of your project: ${e.message}")
128 | uiCallback.onErrorOccurred("Failed to make a backup of your project! ${e.message}")
129 | return
130 | }
131 |
132 | uiCallback.onStatusUpdate("Project backed up successfully!")
133 |
134 | // Pull out information about the designer for later use, if possible
135 | val localResFolder = File(MainBase.CURRENT_DIR, RES_FOLDER_PATH)
136 | val listItemDevAbout = File(File(localResFolder, "layout"), "list_item_about_dev.xml")
137 | if (listItemDevAbout.exists()) {
138 | MainBase.LOG("[INFO]: Extracting information from ${cleanupPath(listItemDevAbout.absolutePath)}")
139 | uiCallback.onStatusUpdate("Extracting information from ${cleanupPath(listItemDevAbout.absolutePath)}")
140 | try {
141 | val contents = Files.readAllBytes(Paths.get(listItemDevAbout.absolutePath))
142 | val contentsStr = String(contents, Charset.forName("UTF-8"))
143 |
144 | val findStrOne = "android:tag=\""
145 | var start = contentsStr.indexOf(findStrOne) + findStrOne.length
146 | var end = contentsStr.indexOf("\"", start + 1)
147 | OLD_ABOUT_BUTTON1_LINK = contentsStr.substring(start, end)
148 | start = contentsStr.indexOf(findStrOne, end + 1) + findStrOne.length
149 | end = contentsStr.indexOf("\"", start + 1)
150 | OLD_ABOUT_BUTTON2_LINK = contentsStr.substring(start, end)
151 |
152 | val findStrTwo = "android:text=\""
153 | start = contentsStr.indexOf("