Search in sources :

Example 16 with ImportExportException

use of com.ichi2.anki.exception.ImportExportException in project Anki-Android by ankidroid.

the class ZipFile method exportInto.

/**
 * Export source database into new destination database Note: The following python syntax isn't supported in
 * Android: for row in mSrc.db.execute("select * from cards where id in "+ids2str(cids)): therefore we use a
 * different method for copying tables
 *
 * @param path String path to destination database
 * @throws JSONException
 * @throws IOException
 */
public void exportInto(@NonNull String path, Context context) throws JSONException, IOException, ImportExportException {
    // create a new collection at the target
    new File(path).delete();
    Collection dst = Storage.Collection(context, path);
    mSrc = mCol;
    // find cards
    Long[] cids = cardIds();
    // attach dst to src so we can copy data between them. This isn't done in original libanki as Python more
    // flexible
    dst.close();
    Timber.d("Attach DB");
    mSrc.getDb().getDatabase().execSQL("ATTACH '" + path + "' AS DST_DB");
    // copy cards, noting used nids (as unique set)
    Timber.d("Copy cards");
    mSrc.getDb().getDatabase().execSQL("INSERT INTO DST_DB.cards select * from cards where id in " + Utils.ids2str(cids));
    List<Long> uniqueNids = mSrc.getDb().queryLongList("select distinct nid from cards where id in " + Utils.ids2str(cids));
    // notes
    Timber.d("Copy notes");
    String strnids = Utils.ids2str(uniqueNids);
    mSrc.getDb().getDatabase().execSQL("INSERT INTO DST_DB.notes select * from notes where id in " + strnids);
    // remove system tags if not exporting scheduling info
    if (!mIncludeSched) {
        Timber.d("Stripping system tags from list");
        ArrayList<String> srcTags = mSrc.getDb().queryStringList("select tags from notes where id in " + strnids);
        ArrayList<Object[]> args = new ArrayList<>(srcTags.size());
        Object[] arg = new Object[2];
        for (int row = 0; row < srcTags.size(); row++) {
            arg[0] = removeSystemTags(srcTags.get(row));
            arg[1] = uniqueNids.get(row);
            args.add(row, arg);
        }
        mSrc.getDb().executeMany("UPDATE DST_DB.notes set tags=? where id=?", args);
    }
    // models used by the notes
    Timber.d("Finding models used by notes");
    ArrayList<Long> mids = mSrc.getDb().queryLongList("select distinct mid from DST_DB.notes where id in " + strnids);
    // card history and revlog
    if (mIncludeSched) {
        Timber.d("Copy history and revlog");
        mSrc.getDb().getDatabase().execSQL("insert into DST_DB.revlog select * from revlog where cid in " + Utils.ids2str(cids));
        // reopen collection to destination database (different from original python code)
        mSrc.getDb().getDatabase().execSQL("DETACH DST_DB");
        dst.reopen();
    } else {
        Timber.d("Detaching destination db and reopening");
        // first reopen collection to destination database (different from original python code)
        mSrc.getDb().getDatabase().execSQL("DETACH DST_DB");
        dst.reopen();
        // then need to reset card state
        Timber.d("Resetting cards");
        dst.getSched().resetCards(cids);
    }
    // models - start with zero
    Timber.d("Copy models");
    for (Model m : mSrc.getModels().all()) {
        if (mids.contains(m.getLong("id"))) {
            dst.getModels().update(m);
        }
    }
    // decks
    Timber.d("Copy decks");
    java.util.Collection<Long> dids = null;
    if (mDid != null) {
        dids = new HashSet<>(mSrc.getDecks().children(mDid).values());
        dids.add(mDid);
    }
    JSONObject dconfs = new JSONObject();
    for (Deck d : mSrc.getDecks().all()) {
        if ("1".equals(d.getString("id"))) {
            continue;
        }
        if (dids != null && !dids.contains(d.getLong("id"))) {
            continue;
        }
        if (d.isStd() && d.getLong("conf") != 1L) {
            if (mIncludeSched) {
                dconfs.put(Long.toString(d.getLong("conf")), true);
            }
        }
        Deck destinationDeck = d.deepClone();
        if (!mIncludeSched) {
            // scheduling not included, so reset deck settings to default
            destinationDeck.put("conf", 1);
        }
        dst.getDecks().update(destinationDeck);
    }
    // copy used deck confs
    Timber.d("Copy deck options");
    for (DeckConfig dc : mSrc.getDecks().allConf()) {
        if (dconfs.has(dc.getString("id"))) {
            dst.getDecks().updateConf(dc);
        }
    }
    // find used media
    Timber.d("Find used media");
    JSONObject media = new JSONObject();
    mMediaDir = mSrc.getMedia().dir();
    if (mIncludeMedia) {
        ArrayList<Long> mid = mSrc.getDb().queryLongList("select mid from notes where id in " + strnids);
        ArrayList<String> flds = mSrc.getDb().queryStringList("select flds from notes where id in " + strnids);
        for (int idx = 0; idx < mid.size(); idx++) {
            for (String file : mSrc.getMedia().filesInStr(mid.get(idx), flds.get(idx))) {
                // skip files in subdirs
                if (file.contains(File.separator)) {
                    continue;
                }
                media.put(file, true);
            }
        }
        if (mMediaDir != null) {
            for (File f : new File(mMediaDir).listFiles()) {
                if (f.isDirectory()) {
                    continue;
                }
                String fname = f.getName();
                if (fname.startsWith("_")) {
                    // Loop through every model that will be exported, and check if it contains a reference to f
                    for (JSONObject model : mSrc.getModels().all()) {
                        if (_modelHasMedia(model, fname)) {
                            media.put(fname, true);
                            break;
                        }
                    }
                }
            }
        }
    }
    JSONArray keys = media.names();
    if (keys != null) {
        mMediaFiles.ensureCapacity(keys.length());
        addAll(mMediaFiles, keys.stringIterable());
    }
    Timber.d("Cleanup");
    dst.setCrt(mSrc.getCrt());
    // todo: tags?
    mCount = dst.cardCount();
    dst.setMod();
    postExport();
    dst.close();
}
Also used : ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray) SuppressLint(android.annotation.SuppressLint) JSONObject(com.ichi2.utils.JSONObject) JSONObject(com.ichi2.utils.JSONObject) File(java.io.File)

Example 17 with ImportExportException

use of com.ichi2.anki.exception.ImportExportException in project Anki-Android by ankidroid.

the class ZipFile method exportFiltered.

private JSONObject exportFiltered(ZipFile z, String path, Context context) throws IOException, JSONException, ImportExportException {
    // export into the anki2 file
    String colfile = path.replace(".apkg", ".anki2");
    super.exportInto(colfile, context);
    z.write(colfile, CollectionHelper.COLLECTION_FILENAME);
    // and media
    prepareMedia();
    JSONObject media = _exportMedia(z, mMediaFiles, mCol.getMedia().dir());
    // tidy up intermediate files
    SQLiteDatabase.deleteDatabase(new File(colfile));
    SQLiteDatabase.deleteDatabase(new File(path.replace(".apkg", ".media.ad.db2")));
    String tempPath = path.replace(".apkg", ".media");
    File file = new File(tempPath);
    if (file.exists()) {
        String deleteCmd = "rm -r " + tempPath;
        Runtime runtime = Runtime.getRuntime();
        try {
            runtime.exec(deleteCmd);
        } catch (IOException ignored) {
            Timber.w(ignored);
        }
    }
    return media;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) IOException(java.io.IOException) File(java.io.File)

Example 18 with ImportExportException

use of com.ichi2.anki.exception.ImportExportException in project Anki-Android by ankidroid.

the class ImportTest method testAnki2Updates.

@Test
public void testAnki2Updates() throws IOException, ImportExportException {
    // create a new empty deck
    String tmp = Shared.getTestFilePath(getTestContext(), "update1.apkg");
    AnkiPackageImporter imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.run();
    assertEquals(0, imp.getDupes());
    assertEquals(1, imp.getAdded());
    assertEquals(0, imp.getUpdated());
    // importing again should be idempotent
    imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.run();
    assertEquals(1, imp.getDupes());
    assertEquals(0, imp.getAdded());
    assertEquals(0, imp.getUpdated());
    // importing a newer note should update
    assertEquals(1, mTestCol.noteCount());
    assertTrue(mTestCol.getDb().queryString("select flds from notes").startsWith("hello"));
    tmp = Shared.getTestFilePath(getTestContext(), "update2.apkg");
    imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.run();
    assertEquals(1, imp.getDupes());
    assertEquals(0, imp.getAdded());
    assertEquals(1, imp.getUpdated());
    assertTrue(mTestCol.getDb().queryString("select flds from notes").startsWith("goodbye"));
}
Also used : AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) Test(org.junit.Test) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest)

Example 19 with ImportExportException

use of com.ichi2.anki.exception.ImportExportException in project Anki-Android by ankidroid.

the class ImportTest method testAnki2DiffmodelTemplates.

@Test
public void testAnki2DiffmodelTemplates() throws IOException, JSONException, ImportExportException {
    // different from the above as this one tests only the template text being
    // changed, not the number of cards/fields
    // import the first version of the model
    String tmp = Shared.getTestFilePath(getTestContext(), "diffmodeltemplates-1.apkg");
    AnkiPackageImporter imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.setDupeOnSchemaChange(true);
    imp.run();
    // then the version with updated template
    tmp = Shared.getTestFilePath(getTestContext(), "diffmodeltemplates-2.apkg");
    imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.setDupeOnSchemaChange(true);
    imp.run();
    // collection should contain the note we imported
    assertEquals(1, mTestCol.noteCount());
    // the front template should contain the text added in the 2nd package
    Long tcid = mTestCol.findCards("").get(0);
    Note tnote = mTestCol.getCard(tcid).note();
    assertTrue(mTestCol.findTemplates(tnote).get(0).getString("qfmt").contains("Changed Front Template"));
}
Also used : AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) Note(com.ichi2.libanki.Note) Test(org.junit.Test) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest)

Example 20 with ImportExportException

use of com.ichi2.anki.exception.ImportExportException in project Anki-Android by ankidroid.

the class ImportTest method testDupeIgnore.

/**
 * Custom tests for AnkiDroid.
 */
@Test
public void testDupeIgnore() throws IOException, ImportExportException {
    // create a new empty deck
    String tmp = Shared.getTestFilePath(getTestContext(), "update1.apkg");
    AnkiPackageImporter imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.run();
    tmp = Shared.getTestFilePath(getTestContext(), "update3.apkg");
    imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.run();
    // there is a dupe, but it was ignored
    assertEquals(1, imp.getDupes());
    assertEquals(0, imp.getAdded());
    assertEquals(0, imp.getUpdated());
}
Also used : AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) Test(org.junit.Test) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest)

Aggregations

Test (org.junit.Test)14 File (java.io.File)13 AnkiPackageImporter (com.ichi2.libanki.importer.AnkiPackageImporter)11 InstrumentedTest (com.ichi2.anki.tests.InstrumentedTest)5 Collection (com.ichi2.libanki.Collection)5 JSONObject (com.ichi2.utils.JSONObject)5 RobolectricTest (com.ichi2.anki.RobolectricTest)4 Note (com.ichi2.libanki.Note)4 Anki2Importer (com.ichi2.libanki.importer.Anki2Importer)4 Importer (com.ichi2.libanki.importer.Importer)4 NoteImporter (com.ichi2.libanki.importer.NoteImporter)4 TextImporter (com.ichi2.libanki.importer.TextImporter)4 FileOutputStream (java.io.FileOutputStream)4 IOException (java.io.IOException)4 ImportExportException (com.ichi2.anki.exception.ImportExportException)2 JSONArray (com.ichi2.utils.JSONArray)2 UnzipFile (com.ichi2.utils.UnzipFile)2 FileNotFoundException (java.io.FileNotFoundException)2 Path (java.nio.file.Path)2 ArrayList (java.util.ArrayList)2