Merge pull request #13352 from theimpulson/path
Port path related changes from refactor
This commit is contained in:
commit
f1c608b396
6 changed files with 78 additions and 111 deletions
|
|
@ -16,7 +16,6 @@ import androidx.activity.result.ActivityResultLauncher;
|
|||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
|
|
@ -35,12 +34,10 @@ import org.schabi.newpipe.streams.io.StoredFileHelper;
|
|||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.ZipHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
|
@ -70,13 +67,10 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
|
|||
@Override
|
||||
public void onCreatePreferences(@Nullable final Bundle savedInstanceState,
|
||||
@Nullable final String rootKey) {
|
||||
final File homeDir = ContextCompat.getDataDir(requireContext());
|
||||
Objects.requireNonNull(homeDir);
|
||||
manager = new ImportExportManager(new BackupFileLocator(homeDir));
|
||||
manager = new ImportExportManager(new BackupFileLocator(requireContext()));
|
||||
|
||||
importExportDataPathKey = getString(R.string.import_export_data_path);
|
||||
|
||||
|
||||
addPreferencesFromResourceRegistry();
|
||||
|
||||
final Preference importDataPreference = requirePreference(R.string.import_data);
|
||||
|
|
@ -204,9 +198,7 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
|
|||
}
|
||||
|
||||
try {
|
||||
if (!manager.ensureDbDirectoryExists()) {
|
||||
throw new IOException("Could not create databases dir");
|
||||
}
|
||||
manager.ensureDbDirectoryExists();
|
||||
|
||||
// replace the current database
|
||||
if (!manager.extractDb(file)) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package org.schabi.newpipe.settings.export
|
||||
|
||||
import java.io.File
|
||||
import android.content.Context
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.div
|
||||
|
||||
/**
|
||||
* Locates specific files of NewPipe based on the home directory of the app.
|
||||
*/
|
||||
class BackupFileLocator(private val homeDir: File) {
|
||||
class BackupFileLocator(context: Context) {
|
||||
companion object {
|
||||
const val FILE_NAME_DB = "newpipe.db"
|
||||
|
||||
|
|
@ -17,13 +19,8 @@ class BackupFileLocator(private val homeDir: File) {
|
|||
const val FILE_NAME_JSON_PREFS = "preferences.json"
|
||||
}
|
||||
|
||||
val dbDir by lazy { File(homeDir, "/databases") }
|
||||
|
||||
val db by lazy { File(dbDir, FILE_NAME_DB) }
|
||||
|
||||
val dbJournal by lazy { File(dbDir, "$FILE_NAME_DB-journal") }
|
||||
|
||||
val dbShm by lazy { File(dbDir, "$FILE_NAME_DB-shm") }
|
||||
|
||||
val dbWal by lazy { File(dbDir, "$FILE_NAME_DB-wal") }
|
||||
val db: Path = context.getDatabasePath(FILE_NAME_DB).toPath()
|
||||
val dbJournal: Path = db.resolveSibling("$FILE_NAME_DB-journal")
|
||||
val dbShm: Path = db.resolveSibling("$FILE_NAME_DB-shm")
|
||||
val dbWal: Path = db.resolveSibling("$FILE_NAME_DB-wal")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import java.io.FileNotFoundException
|
|||
import java.io.IOException
|
||||
import java.io.ObjectOutputStream
|
||||
import java.util.zip.ZipOutputStream
|
||||
import kotlin.io.path.createParentDirectories
|
||||
import kotlin.io.path.deleteIfExists
|
||||
import org.schabi.newpipe.streams.io.SharpOutputStream
|
||||
import org.schabi.newpipe.streams.io.StoredFileHelper
|
||||
import org.schabi.newpipe.util.ZipHelper
|
||||
|
|
@ -28,11 +30,8 @@ class ImportExportManager(private val fileLocator: BackupFileLocator) {
|
|||
// previous file size, the file will retain part of the previous content and be corrupted
|
||||
ZipOutputStream(SharpOutputStream(file.openAndTruncateStream()).buffered()).use { outZip ->
|
||||
// add the database
|
||||
ZipHelper.addFileToZip(
|
||||
outZip,
|
||||
BackupFileLocator.FILE_NAME_DB,
|
||||
fileLocator.db.path
|
||||
)
|
||||
val name = BackupFileLocator.FILE_NAME_DB
|
||||
ZipHelper.addFileToZip(outZip, name, fileLocator.db)
|
||||
|
||||
// add the legacy vulnerable serialized preferences (will be removed in the future)
|
||||
ZipHelper.addFileToZip(
|
||||
|
|
@ -61,11 +60,10 @@ class ImportExportManager(private val fileLocator: BackupFileLocator) {
|
|||
|
||||
/**
|
||||
* Tries to create database directory if it does not exist.
|
||||
*
|
||||
* @return Whether the directory exists afterwards.
|
||||
*/
|
||||
fun ensureDbDirectoryExists(): Boolean {
|
||||
return fileLocator.dbDir.exists() || fileLocator.dbDir.mkdir()
|
||||
@Throws(IOException::class)
|
||||
fun ensureDbDirectoryExists() {
|
||||
fileLocator.db.createParentDirectories()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -75,16 +73,13 @@ class ImportExportManager(private val fileLocator: BackupFileLocator) {
|
|||
* @return true if the database was successfully extracted, false otherwise
|
||||
*/
|
||||
fun extractDb(file: StoredFileHelper): Boolean {
|
||||
val success = ZipHelper.extractFileFromZip(
|
||||
file,
|
||||
BackupFileLocator.FILE_NAME_DB,
|
||||
fileLocator.db.path
|
||||
)
|
||||
val name = BackupFileLocator.FILE_NAME_DB
|
||||
val success = ZipHelper.extractFileFromZip(file, name, fileLocator.db)
|
||||
|
||||
if (success) {
|
||||
fileLocator.dbJournal.delete()
|
||||
fileLocator.dbWal.delete()
|
||||
fileLocator.dbShm.delete()
|
||||
fileLocator.dbJournal.deleteIfExists()
|
||||
fileLocator.dbWal.deleteIfExists()
|
||||
fileLocator.dbShm.deleteIfExists()
|
||||
}
|
||||
|
||||
return success
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ import org.schabi.newpipe.streams.io.StoredFileHelper;
|
|||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
|
@ -37,9 +37,6 @@ import java.util.zip.ZipOutputStream;
|
|||
*/
|
||||
|
||||
public final class ZipHelper {
|
||||
|
||||
private static final int BUFFER_SIZE = 2048;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface InputStreamConsumer {
|
||||
void acceptStream(InputStream inputStream) throws IOException;
|
||||
|
|
@ -55,17 +52,17 @@ public final class ZipHelper {
|
|||
|
||||
|
||||
/**
|
||||
* This function helps to create zip files. Caution this will overwrite the original file.
|
||||
* This function helps to create zip files. Caution, this will overwrite the original file.
|
||||
*
|
||||
* @param outZip the ZipOutputStream where the data should be stored in
|
||||
* @param nameInZip the path of the file inside the zip
|
||||
* @param fileOnDisk the path of the file on the disk that should be added to zip
|
||||
* @param path the path of the file on the disk that should be added to zip
|
||||
*/
|
||||
public static void addFileToZip(final ZipOutputStream outZip,
|
||||
final String nameInZip,
|
||||
final String fileOnDisk) throws IOException {
|
||||
try (FileInputStream fi = new FileInputStream(fileOnDisk)) {
|
||||
addFileToZip(outZip, nameInZip, fi);
|
||||
final Path path) throws IOException {
|
||||
try (var inputStream = Files.newInputStream(path)) {
|
||||
addFileToZip(outZip, nameInZip, inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,13 +77,13 @@ public final class ZipHelper {
|
|||
final String nameInZip,
|
||||
final OutputStreamConsumer streamConsumer) throws IOException {
|
||||
final byte[] bytes;
|
||||
try (ByteArrayOutputStream byteOutput = new ByteArrayOutputStream()) {
|
||||
try (var byteOutput = new ByteArrayOutputStream()) {
|
||||
streamConsumer.acceptStream(byteOutput);
|
||||
bytes = byteOutput.toByteArray();
|
||||
}
|
||||
|
||||
try (ByteArrayInputStream byteInput = new ByteArrayInputStream(bytes)) {
|
||||
ZipHelper.addFileToZip(outZip, nameInZip, byteInput);
|
||||
try (var byteInput = new ByteArrayInputStream(bytes)) {
|
||||
addFileToZip(outZip, nameInZip, byteInput);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -97,49 +94,26 @@ public final class ZipHelper {
|
|||
* @param nameInZip the path of the file inside the zip
|
||||
* @param inputStream the content to put inside the file
|
||||
*/
|
||||
public static void addFileToZip(final ZipOutputStream outZip,
|
||||
final String nameInZip,
|
||||
final InputStream inputStream) throws IOException {
|
||||
final byte[] data = new byte[BUFFER_SIZE];
|
||||
try (BufferedInputStream bufferedInputStream =
|
||||
new BufferedInputStream(inputStream, BUFFER_SIZE)) {
|
||||
final ZipEntry entry = new ZipEntry(nameInZip);
|
||||
outZip.putNextEntry(entry);
|
||||
int count;
|
||||
while ((count = bufferedInputStream.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
outZip.write(data, 0, count);
|
||||
}
|
||||
}
|
||||
private static void addFileToZip(final ZipOutputStream outZip,
|
||||
final String nameInZip,
|
||||
final InputStream inputStream) throws IOException {
|
||||
outZip.putNextEntry(new ZipEntry(nameInZip));
|
||||
inputStream.transferTo(outZip);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will extract data from ZipInputStream. Caution this will overwrite the original file.
|
||||
* This will extract data from ZipInputStream. Caution, this will overwrite the original file.
|
||||
*
|
||||
* @param zipFile the zip file to extract from
|
||||
* @param nameInZip the path of the file inside the zip
|
||||
* @param fileOnDisk the path of the file on the disk where the data should be extracted to
|
||||
* @param path the path of the file on the disk where the data should be extracted to
|
||||
* @return will return true if the file was found within the zip file
|
||||
*/
|
||||
public static boolean extractFileFromZip(final StoredFileHelper zipFile,
|
||||
final String nameInZip,
|
||||
final String fileOnDisk) throws IOException {
|
||||
return extractFileFromZip(zipFile, nameInZip, input -> {
|
||||
// delete old file first
|
||||
final File oldFile = new File(fileOnDisk);
|
||||
if (oldFile.exists()) {
|
||||
if (!oldFile.delete()) {
|
||||
throw new IOException("Could not delete " + fileOnDisk);
|
||||
}
|
||||
}
|
||||
|
||||
final byte[] data = new byte[BUFFER_SIZE];
|
||||
try (FileOutputStream outFile = new FileOutputStream(fileOnDisk)) {
|
||||
int count;
|
||||
while ((count = input.read(data)) != -1) {
|
||||
outFile.write(data, 0, count);
|
||||
}
|
||||
}
|
||||
});
|
||||
final Path path) throws IOException {
|
||||
return extractFileFromZip(zipFile, nameInZip, input ->
|
||||
Files.copy(input, path, StandardCopyOption.REPLACE_EXISTING));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package org.schabi.newpipe.settings
|
|||
import android.content.SharedPreferences
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
import kotlin.io.path.createTempFile
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.fileSize
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito
|
||||
|
|
@ -47,10 +49,10 @@ class ImportAllCombinationsTest {
|
|||
BackupFileLocator::class.java,
|
||||
Mockito.withSettings().stubOnly()
|
||||
)
|
||||
val db = File.createTempFile("newpipe_", "")
|
||||
val dbJournal = File.createTempFile("newpipe_", "")
|
||||
val dbWal = File.createTempFile("newpipe_", "")
|
||||
val dbShm = File.createTempFile("newpipe_", "")
|
||||
val db = createTempFile("newpipe_", "")
|
||||
val dbJournal = createTempFile("newpipe_", "")
|
||||
val dbWal = createTempFile("newpipe_", "")
|
||||
val dbShm = createTempFile("newpipe_", "")
|
||||
Mockito.`when`(fileLocator.db).thenReturn(db)
|
||||
Mockito.`when`(fileLocator.dbJournal).thenReturn(dbJournal)
|
||||
Mockito.`when`(fileLocator.dbShm).thenReturn(dbShm)
|
||||
|
|
@ -62,7 +64,7 @@ class ImportAllCombinationsTest {
|
|||
Assert.assertFalse(dbJournal.exists())
|
||||
Assert.assertFalse(dbWal.exists())
|
||||
Assert.assertFalse(dbShm.exists())
|
||||
Assert.assertTrue("database file size is zero", Files.size(db.toPath()) > 0)
|
||||
Assert.assertTrue("database file size is zero", db.fileSize() > 0)
|
||||
}
|
||||
} else {
|
||||
runTest {
|
||||
|
|
@ -70,7 +72,7 @@ class ImportAllCombinationsTest {
|
|||
Assert.assertTrue(dbJournal.exists())
|
||||
Assert.assertTrue(dbWal.exists())
|
||||
Assert.assertTrue(dbShm.exists())
|
||||
Assert.assertEquals(0, Files.size(db.toPath()))
|
||||
Assert.assertEquals(0, db.fileSize())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,15 @@ import android.content.SharedPreferences
|
|||
import com.grack.nanojson.JsonParser
|
||||
import java.io.File
|
||||
import java.io.ObjectInputStream
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.util.zip.ZipFile
|
||||
import kotlin.io.path.createTempDirectory
|
||||
import kotlin.io.path.createTempFile
|
||||
import kotlin.io.path.deleteIfExists
|
||||
import kotlin.io.path.div
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.fileSize
|
||||
import kotlin.io.path.inputStream
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertThrows
|
||||
|
|
@ -46,7 +53,7 @@ class ImportExportManagerTest {
|
|||
|
||||
@Test
|
||||
fun `The settings must be exported successfully in the correct format`() {
|
||||
val db = File(classloader.getResource("settings/newpipe.db")!!.file)
|
||||
val db = Paths.get(classloader.getResource("settings/newpipe.db")!!.toURI())
|
||||
`when`(fileLocator.db).thenReturn(db)
|
||||
|
||||
val expectedPreferences = mapOf("such pref" to "much wow")
|
||||
|
|
@ -81,29 +88,29 @@ class ImportExportManagerTest {
|
|||
|
||||
@Test
|
||||
fun `Ensuring db directory existence must work`() {
|
||||
val dir = Files.createTempDirectory("newpipe_").toFile()
|
||||
Assume.assumeTrue(dir.delete())
|
||||
`when`(fileLocator.dbDir).thenReturn(dir)
|
||||
val path = createTempDirectory("newpipe_") / BackupFileLocator.FILE_NAME_DB
|
||||
Assume.assumeTrue(path.parent.deleteIfExists())
|
||||
`when`(fileLocator.db).thenReturn(path)
|
||||
|
||||
ImportExportManager(fileLocator).ensureDbDirectoryExists()
|
||||
assertTrue(dir.exists())
|
||||
assertTrue(path.parent.exists())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Ensuring db directory existence must work when the directory already exists`() {
|
||||
val dir = Files.createTempDirectory("newpipe_").toFile()
|
||||
`when`(fileLocator.dbDir).thenReturn(dir)
|
||||
val path = createTempDirectory("newpipe_") / BackupFileLocator.FILE_NAME_DB
|
||||
`when`(fileLocator.db).thenReturn(path)
|
||||
|
||||
ImportExportManager(fileLocator).ensureDbDirectoryExists()
|
||||
assertTrue(dir.exists())
|
||||
assertTrue(path.parent.exists())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `The database must be extracted from the zip file`() {
|
||||
val db = File.createTempFile("newpipe_", "")
|
||||
val dbJournal = File.createTempFile("newpipe_", "")
|
||||
val dbWal = File.createTempFile("newpipe_", "")
|
||||
val dbShm = File.createTempFile("newpipe_", "")
|
||||
val db = createTempFile("newpipe_", "")
|
||||
val dbJournal = createTempFile("newpipe_", "")
|
||||
val dbWal = createTempFile("newpipe_", "")
|
||||
val dbShm = createTempFile("newpipe_", "")
|
||||
`when`(fileLocator.db).thenReturn(db)
|
||||
`when`(fileLocator.dbJournal).thenReturn(dbJournal)
|
||||
`when`(fileLocator.dbShm).thenReturn(dbShm)
|
||||
|
|
@ -117,15 +124,15 @@ class ImportExportManagerTest {
|
|||
assertFalse(dbJournal.exists())
|
||||
assertFalse(dbWal.exists())
|
||||
assertFalse(dbShm.exists())
|
||||
assertTrue("database file size is zero", Files.size(db.toPath()) > 0)
|
||||
assertTrue("database file size is zero", db.fileSize() > 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Extracting the database from an empty zip must not work`() {
|
||||
val db = File.createTempFile("newpipe_", "")
|
||||
val dbJournal = File.createTempFile("newpipe_", "")
|
||||
val dbWal = File.createTempFile("newpipe_", "")
|
||||
val dbShm = File.createTempFile("newpipe_", "")
|
||||
val db = createTempFile("newpipe_", "")
|
||||
val dbJournal = createTempFile("newpipe_", "")
|
||||
val dbWal = createTempFile("newpipe_", "")
|
||||
val dbShm = createTempFile("newpipe_", "")
|
||||
`when`(fileLocator.db).thenReturn(db)
|
||||
|
||||
val emptyZip = File(classloader.getResource("settings/nodb_noser_nojson.zip")?.file!!)
|
||||
|
|
@ -136,7 +143,7 @@ class ImportExportManagerTest {
|
|||
assertTrue(dbJournal.exists())
|
||||
assertTrue(dbWal.exists())
|
||||
assertTrue(dbShm.exists())
|
||||
assertEquals(0, Files.size(db.toPath()))
|
||||
assertEquals(0, db.fileSize())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue