Merge branch 'bug-fixes-1.7' into 'master'
Bug fixes 1.7 Closes #1678 and #1757 See merge request fdroid/fdroidclient!820
This commit is contained in:
commit
fac36457ea
@ -42,6 +42,7 @@
|
|||||||
android:id="@+id/find_people_button"
|
android:id="@+id/find_people_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:maxEms="16"
|
||||||
android:text="@string/nearby_splash__find_people_button"
|
android:text="@string/nearby_splash__find_people_button"
|
||||||
style="@style/DetailsSecondaryButtonStyle"
|
style="@style/DetailsSecondaryButtonStyle"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||||
@ -85,6 +86,7 @@
|
|||||||
android:id="@+id/request_read_external_storage_button"
|
android:id="@+id/request_read_external_storage_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:maxEms="16"
|
||||||
android:text="@string/nearby_splash__request_permission"
|
android:text="@string/nearby_splash__request_permission"
|
||||||
style="@style/DetailsSecondaryButtonStyle"
|
style="@style/DetailsSecondaryButtonStyle"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -37,6 +37,9 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:backgroundTint="@color/swap_light_blue"
|
android:backgroundTint="@color/swap_light_blue"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
|
android:maxEms="10"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
android:text="@string/menu_install"
|
android:text="@string/menu_install"
|
||||||
tools:ignore="UnusedAttribute" />
|
tools:ignore="UnusedAttribute" />
|
||||||
|
|
||||||
|
@ -28,13 +28,11 @@ public class DeleteCacheService extends JobIntentService {
|
|||||||
Log.w(TAG, "Deleting all cached contents!");
|
Log.w(TAG, "Deleting all cached contents!");
|
||||||
try {
|
try {
|
||||||
File cacheDir = getCacheDir();
|
File cacheDir = getCacheDir();
|
||||||
if (cacheDir != null) {
|
FileUtils.deleteDirectory(cacheDir);
|
||||||
FileUtils.deleteDirectory(cacheDir);
|
|
||||||
}
|
|
||||||
for (File dir : ContextCompat.getExternalCacheDirs(this)) {
|
for (File dir : ContextCompat.getExternalCacheDirs(this)) {
|
||||||
FileUtils.deleteDirectory(dir);
|
FileUtils.deleteDirectory(dir);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Throwable e) { // NOPMD
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -414,7 +414,7 @@ public class IndexUpdater {
|
|||||||
|
|
||||||
Utils.debugLog(TAG, "Saving new signing certificate in the database for " + repo.address);
|
Utils.debugLog(TAG, "Saving new signing certificate in the database for " + repo.address);
|
||||||
ContentValues values = new ContentValues(2);
|
ContentValues values = new ContentValues(2);
|
||||||
values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatDate(new Date(), ""));
|
values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatTime(new Date(), ""));
|
||||||
values.put(RepoTable.Cols.SIGNING_CERT, Hasher.hex(rawCertFromJar));
|
values.put(RepoTable.Cols.SIGNING_CERT, Hasher.hex(rawCertFromJar));
|
||||||
RepoProvider.Helper.update(context, repo, values);
|
RepoProvider.Helper.update(context, repo, values);
|
||||||
}
|
}
|
||||||
|
@ -470,7 +470,7 @@ public class IndexV1Updater extends IndexUpdater {
|
|||||||
}
|
}
|
||||||
Utils.debugLog(TAG, "Saving new signing certificate to database for " + repo.address);
|
Utils.debugLog(TAG, "Saving new signing certificate to database for " + repo.address);
|
||||||
ContentValues values = new ContentValues(2);
|
ContentValues values = new ContentValues(2);
|
||||||
values.put(Schema.RepoTable.Cols.LAST_UPDATED, Utils.formatDate(new Date(), ""));
|
values.put(Schema.RepoTable.Cols.LAST_UPDATED, Utils.formatTime(new Date(), ""));
|
||||||
values.put(Schema.RepoTable.Cols.SIGNING_CERT, Hasher.hex(rawCertFromJar));
|
values.put(Schema.RepoTable.Cols.SIGNING_CERT, Hasher.hex(rawCertFromJar));
|
||||||
RepoProvider.Helper.update(context, repo, values);
|
RepoProvider.Helper.update(context, repo, values);
|
||||||
repo.signingCertificate = certFromJar;
|
repo.signingCertificate = certFromJar;
|
||||||
|
@ -236,7 +236,7 @@ public class UpdateService extends JobIntentService {
|
|||||||
Utils.debugLog(TAG, "scheduling update because there is good internet");
|
Utils.debugLog(TAG, "scheduling update because there is good internet");
|
||||||
schedule(context);
|
schedule(context);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Throwable e) { // NOPMD
|
||||||
Utils.debugLog(TAG, e.getMessage());
|
Utils.debugLog(TAG, e.getMessage());
|
||||||
}
|
}
|
||||||
isScheduleIfStillOnWifiRunning = false;
|
isScheduleIfStillOnWifiRunning = false;
|
||||||
|
@ -79,6 +79,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -96,6 +97,8 @@ public final class Utils {
|
|||||||
private static final SimpleDateFormat TIME_FORMAT =
|
private static final SimpleDateFormat TIME_FORMAT =
|
||||||
new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss", Locale.ENGLISH);
|
new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss", Locale.ENGLISH);
|
||||||
|
|
||||||
|
private static final TimeZone UTC = TimeZone.getTimeZone("Etc/GMT");
|
||||||
|
|
||||||
private static final String[] FRIENDLY_SIZE_FORMAT = {
|
private static final String[] FRIENDLY_SIZE_FORMAT = {
|
||||||
"%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB",
|
"%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB",
|
||||||
};
|
};
|
||||||
@ -384,7 +387,7 @@ public final class Utils {
|
|||||||
}
|
}
|
||||||
ret = formatter.toString();
|
ret = formatter.toString();
|
||||||
formatter.close();
|
formatter.close();
|
||||||
} catch (Exception e) {
|
} catch (Throwable e) { // NOPMD
|
||||||
Log.w(TAG, "Unable to get certificate fingerprint", e);
|
Log.w(TAG, "Unable to get certificate fingerprint", e);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -583,6 +586,7 @@ public final class Utils {
|
|||||||
}
|
}
|
||||||
Date result;
|
Date result;
|
||||||
try {
|
try {
|
||||||
|
format.setTimeZone(UTC);
|
||||||
result = format.parse(str);
|
result = format.parse(str);
|
||||||
} catch (ArrayIndexOutOfBoundsException | NumberFormatException | ParseException e) {
|
} catch (ArrayIndexOutOfBoundsException | NumberFormatException | ParseException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -595,21 +599,34 @@ public final class Utils {
|
|||||||
if (date == null) {
|
if (date == null) {
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
format.setTimeZone(UTC);
|
||||||
return format.format(date);
|
return format.format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a date string into UTC time
|
||||||
|
*/
|
||||||
public static Date parseDate(String str, Date fallback) {
|
public static Date parseDate(String str, Date fallback) {
|
||||||
return parseDateFormat(DATE_FORMAT, str, fallback);
|
return parseDateFormat(DATE_FORMAT, str, fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats UTC time into a date string
|
||||||
|
*/
|
||||||
public static String formatDate(Date date, String fallback) {
|
public static String formatDate(Date date, String fallback) {
|
||||||
return formatDateFormat(DATE_FORMAT, date, fallback);
|
return formatDateFormat(DATE_FORMAT, date, fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a date/time string into UTC time
|
||||||
|
*/
|
||||||
public static Date parseTime(String str, Date fallback) {
|
public static Date parseTime(String str, Date fallback) {
|
||||||
return parseDateFormat(TIME_FORMAT, str, fallback);
|
return parseDateFormat(TIME_FORMAT, str, fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats UTC time into a date/time string
|
||||||
|
*/
|
||||||
public static String formatTime(Date date, String fallback) {
|
public static String formatTime(Date date, String fallback) {
|
||||||
return formatDateFormat(TIME_FORMAT, date, fallback);
|
return formatDateFormat(TIME_FORMAT, date, fallback);
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,8 @@ public class Repo extends ValueObject {
|
|||||||
inuse = cursor.getInt(i) == 1;
|
inuse = cursor.getInt(i) == 1;
|
||||||
break;
|
break;
|
||||||
case Cols.LAST_UPDATED:
|
case Cols.LAST_UPDATED:
|
||||||
lastUpdated = Utils.parseTime(cursor.getString(i), null);
|
String dateString = cursor.getString(i);
|
||||||
|
lastUpdated = Utils.parseTime(dateString, Utils.parseDate(dateString, null));
|
||||||
break;
|
break;
|
||||||
case Cols.MAX_AGE:
|
case Cols.MAX_AGE:
|
||||||
maxage = cursor.getInt(i);
|
maxage = cursor.getInt(i);
|
||||||
@ -296,7 +297,7 @@ public class Repo extends ValueObject {
|
|||||||
|
|
||||||
if (values.containsKey(Cols.LAST_UPDATED)) {
|
if (values.containsKey(Cols.LAST_UPDATED)) {
|
||||||
final String dateString = values.getAsString(Cols.LAST_UPDATED);
|
final String dateString = values.getAsString(Cols.LAST_UPDATED);
|
||||||
lastUpdated = Utils.parseTime(dateString, null);
|
lastUpdated = Utils.parseTime(dateString, Utils.parseDate(dateString, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (values.containsKey(Cols.MAX_AGE)) {
|
if (values.containsKey(Cols.MAX_AGE)) {
|
||||||
|
@ -11,7 +11,6 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.fdroid.fdroid.AppUpdateStatusManager;
|
import org.fdroid.fdroid.AppUpdateStatusManager;
|
||||||
import org.fdroid.fdroid.Utils;
|
import org.fdroid.fdroid.Utils;
|
||||||
import org.fdroid.fdroid.data.Schema.RepoTable;
|
import org.fdroid.fdroid.data.Schema.RepoTable;
|
||||||
@ -278,7 +277,8 @@ public class RepoProvider extends FDroidProvider {
|
|||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
if (cursor.getCount() > 0) {
|
if (cursor.getCount() > 0) {
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
lastUpdate = Utils.parseDate(cursor.getString(0), null);
|
String dateString = cursor.getString(0);
|
||||||
|
lastUpdate = Utils.parseTime(dateString, Utils.parseDate(dateString, null));
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
|
@ -265,7 +265,7 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
PackageManager pm = context.getPackageManager();
|
PackageManager pm = context.getPackageManager();
|
||||||
try {
|
try {
|
||||||
pm.getPackageInfo(PRIVILEGED_EXTENSION_PACKAGE_NAME, PackageManager.GET_ACTIVITIES);
|
pm.getPackageInfo(PRIVILEGED_EXTENSION_PACKAGE_NAME, PackageManager.GET_ACTIVITIES);
|
||||||
return true;
|
return pm.getApplicationInfo(PRIVILEGED_EXTENSION_PACKAGE_NAME, 0).enabled;
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -555,11 +555,16 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateAntiFeaturesWarning();
|
updateAntiFeaturesWarning();
|
||||||
buttonSecondaryView.setText(R.string.menu_uninstall);
|
|
||||||
buttonSecondaryView.setVisibility(app.isUninstallable(context) ? View.VISIBLE : View.INVISIBLE);
|
|
||||||
buttonSecondaryView.setOnClickListener(onUnInstallClickListener);
|
|
||||||
buttonPrimaryView.setText(R.string.menu_install);
|
buttonPrimaryView.setText(R.string.menu_install);
|
||||||
buttonPrimaryView.setVisibility(versions.size() > 0 ? View.VISIBLE : View.GONE);
|
buttonPrimaryView.setVisibility(versions.size() > 0 ? View.VISIBLE : View.GONE);
|
||||||
|
buttonSecondaryView.setText(R.string.menu_uninstall);
|
||||||
|
buttonSecondaryView.setVisibility(app.isUninstallable(context) ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
buttonSecondaryView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
callbacks.uninstallApk();
|
||||||
|
}
|
||||||
|
});
|
||||||
if (callbacks.isAppDownloading()) {
|
if (callbacks.isAppDownloading()) {
|
||||||
buttonPrimaryView.setText(R.string.downloading);
|
buttonPrimaryView.setText(R.string.downloading);
|
||||||
buttonPrimaryView.setEnabled(false);
|
buttonPrimaryView.setEnabled(false);
|
||||||
@ -568,22 +573,37 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
} else if (!app.isInstalled(context) && suggestedApk != null) {
|
} else if (!app.isInstalled(context) && suggestedApk != null) {
|
||||||
// Check count > 0 due to incompatible apps resulting in an empty list.
|
// Check count > 0 due to incompatible apps resulting in an empty list.
|
||||||
callbacks.disableAndroidBeam();
|
callbacks.disableAndroidBeam();
|
||||||
|
progressLayout.setVisibility(View.GONE);
|
||||||
// Set Install button and hide second button
|
// Set Install button and hide second button
|
||||||
buttonPrimaryView.setText(R.string.menu_install);
|
buttonPrimaryView.setText(R.string.menu_install);
|
||||||
buttonPrimaryView.setOnClickListener(onInstallClickListener);
|
|
||||||
buttonPrimaryView.setEnabled(true);
|
buttonPrimaryView.setEnabled(true);
|
||||||
buttonLayout.setVisibility(View.VISIBLE);
|
buttonLayout.setVisibility(View.VISIBLE);
|
||||||
progressLayout.setVisibility(View.GONE);
|
buttonPrimaryView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
callbacks.installApk();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if (app.isInstalled(context)) {
|
} else if (app.isInstalled(context)) {
|
||||||
callbacks.enableAndroidBeam();
|
callbacks.enableAndroidBeam();
|
||||||
if (app.canAndWantToUpdate(context) && suggestedApk != null) {
|
if (app.canAndWantToUpdate(context) && suggestedApk != null) {
|
||||||
buttonPrimaryView.setText(R.string.menu_upgrade);
|
buttonPrimaryView.setText(R.string.menu_upgrade);
|
||||||
buttonPrimaryView.setOnClickListener(onUpgradeClickListener);
|
buttonPrimaryView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
callbacks.installApk();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
Apk mediaApk = app.getMediaApkifInstalled(context);
|
Apk mediaApk = app.getMediaApkifInstalled(context);
|
||||||
if (context.getPackageManager().getLaunchIntentForPackage(app.packageName) != null) {
|
if (context.getPackageManager().getLaunchIntentForPackage(app.packageName) != null) {
|
||||||
buttonPrimaryView.setText(R.string.menu_launch);
|
buttonPrimaryView.setText(R.string.menu_launch);
|
||||||
buttonPrimaryView.setOnClickListener(onLaunchClickListener);
|
buttonPrimaryView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
callbacks.launchApk();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if (!app.isApk && mediaApk != null) {
|
} else if (!app.isApk && mediaApk != null) {
|
||||||
final File installedFile = new File(mediaApk.getMediaInstallPath(context), mediaApk.apkName);
|
final File installedFile = new File(mediaApk.getMediaInstallPath(context), mediaApk.apkName);
|
||||||
if (!installedFile.toString().startsWith(context.getApplicationInfo().dataDir)) {
|
if (!installedFile.toString().startsWith(context.getApplicationInfo().dataDir)) {
|
||||||
@ -1324,34 +1344,6 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final View.OnClickListener onInstallClickListener = new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
callbacks.installApk();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final View.OnClickListener onUnInstallClickListener = new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
callbacks.uninstallApk();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final View.OnClickListener onUpgradeClickListener = new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
callbacks.installApk();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final View.OnClickListener onLaunchClickListener = new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
callbacks.launchApk();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private boolean uriIsSetAndCanBeOpened(String s) {
|
private boolean uriIsSetAndCanBeOpened(String s) {
|
||||||
if (TextUtils.isEmpty(s)) {
|
if (TextUtils.isEmpty(s)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -143,6 +143,9 @@
|
|||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
android:layout_marginRight="4dp"
|
android:layout_marginRight="4dp"
|
||||||
android:layout_marginEnd="4dp"
|
android:layout_marginEnd="4dp"
|
||||||
|
android:maxEms="10"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
tools:text="@string/menu_install"/>
|
tools:text="@string/menu_install"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginRight="16dp"
|
android:layout_marginRight="16dp"
|
||||||
|
android:maxEms="10"
|
||||||
android:text="@string/update_all"
|
android:text="@string/update_all"
|
||||||
style="@style/DetailsPrimaryButtonStyle"
|
style="@style/DetailsPrimaryButtonStyle"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
@ -54,6 +55,8 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
|
android:ellipsize="middle"
|
||||||
|
android:singleLine="true"
|
||||||
tools:text="Show apps"
|
tools:text="Show apps"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -10,6 +10,8 @@ import org.robolectric.RuntimeEnvironment;
|
|||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@ -77,9 +79,9 @@ public class UtilsTest {
|
|||||||
assertEquals("three", tripleValue[2]);
|
assertEquals("three", tripleValue[2]);
|
||||||
|
|
||||||
assertNull(Utils.serializeCommaSeparatedString(null));
|
assertNull(Utils.serializeCommaSeparatedString(null));
|
||||||
assertNull(Utils.serializeCommaSeparatedString(new String[] {}));
|
assertNull(Utils.serializeCommaSeparatedString(new String[]{}));
|
||||||
assertEquals("Single", Utils.serializeCommaSeparatedString(new String[] {"Single"}));
|
assertEquals("Single", Utils.serializeCommaSeparatedString(new String[]{"Single"}));
|
||||||
assertEquals("One,TWO,three", Utils.serializeCommaSeparatedString(new String[] {"One", "TWO", "three"}));
|
assertEquals("One,TWO,three", Utils.serializeCommaSeparatedString(new String[]{"One", "TWO", "three"}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -192,4 +194,25 @@ public class UtilsTest {
|
|||||||
}
|
}
|
||||||
// TODO write tests that work with a Certificate
|
// TODO write tests that work with a Certificate
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIndexDatesWithTimeZones() {
|
||||||
|
for (int h = 0; h < 12; h++) {
|
||||||
|
for (int m = 0; m < 60; m = m + 15) {
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT+%d%02d", h, m)));
|
||||||
|
|
||||||
|
String timeString = "2017-11-27_20:13:24";
|
||||||
|
Date time = Utils.parseTime(timeString, null);
|
||||||
|
assertEquals("The String representation must match", timeString, Utils.formatTime(time, null));
|
||||||
|
assertEquals(timeString + " failed to parse", 1511813604000L, time.getTime());
|
||||||
|
assertEquals("time zones should match", -((h * 60) + m), time.getTimezoneOffset());
|
||||||
|
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT+%d%02d", h, m)));
|
||||||
|
String dateString = "2017-11-27";
|
||||||
|
Date date = Utils.parseDate(dateString, null);
|
||||||
|
assertEquals("The String representation must match", dateString, Utils.formatDate(date, null));
|
||||||
|
assertEquals(dateString + " failed to parse", 1511740800000L, date.getTime());
|
||||||
|
assertEquals("time zones should match", -((h * 60) + m), date.getTimezoneOffset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,12 @@ import android.net.Uri;
|
|||||||
import org.fdroid.fdroid.Assert;
|
import org.fdroid.fdroid.Assert;
|
||||||
import org.fdroid.fdroid.BuildConfig;
|
import org.fdroid.fdroid.BuildConfig;
|
||||||
import org.fdroid.fdroid.TestUtils;
|
import org.fdroid.fdroid.TestUtils;
|
||||||
|
import org.fdroid.fdroid.Utils;
|
||||||
import org.fdroid.fdroid.data.Schema.ApkTable.Cols;
|
import org.fdroid.fdroid.data.Schema.ApkTable.Cols;
|
||||||
import org.fdroid.fdroid.data.Schema.RepoTable;
|
import org.fdroid.fdroid.data.Schema.RepoTable;
|
||||||
import org.fdroid.fdroid.mock.MockApk;
|
import org.fdroid.fdroid.mock.MockApk;
|
||||||
import org.fdroid.fdroid.mock.MockRepo;
|
import org.fdroid.fdroid.mock.MockRepo;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
@ -18,6 +20,7 @@ import org.robolectric.annotation.Config;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import static org.fdroid.fdroid.Assert.assertCantDelete;
|
import static org.fdroid.fdroid.Assert.assertCantDelete;
|
||||||
import static org.fdroid.fdroid.Assert.assertResultCount;
|
import static org.fdroid.fdroid.Assert.assertResultCount;
|
||||||
@ -34,6 +37,13 @@ public class ApkProviderTest extends FDroidProviderTest {
|
|||||||
|
|
||||||
private static final String[] PROJ = Cols.ALL;
|
private static final String[] PROJ = Cols.ALL;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setRandomTimeZone() {
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT-%d:%02d",
|
||||||
|
System.currentTimeMillis() % 12, System.currentTimeMillis() % 60)));
|
||||||
|
System.out.println("TIME ZONE for this test: " + TimeZone.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAppApks() {
|
public void testAppApks() {
|
||||||
App fdroidApp = insertApp(context, "org.fdroid.fdroid", "F-Droid");
|
App fdroidApp = insertApp(context, "org.fdroid.fdroid", "F-Droid");
|
||||||
@ -153,7 +163,7 @@ public class ApkProviderTest extends FDroidProviderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCount() {
|
public void testCount() {
|
||||||
String[] projectionCount = new String[] {Cols._COUNT};
|
String[] projectionCount = new String[]{Cols._COUNT};
|
||||||
|
|
||||||
for (int i = 0; i < 13; i++) {
|
for (int i = 0; i < 13; i++) {
|
||||||
Assert.insertApk(context, "com.example", i);
|
Assert.insertApk(context, "com.example", i);
|
||||||
@ -315,12 +325,13 @@ public class ApkProviderTest extends FDroidProviderTest {
|
|||||||
assertNull(apk.added);
|
assertNull(apk.added);
|
||||||
assertNull(apk.hashType);
|
assertNull(apk.hashType);
|
||||||
|
|
||||||
apk.antiFeatures = new String[] {"KnownVuln", "Other anti feature"};
|
apk.antiFeatures = new String[]{"KnownVuln", "Other anti feature"};
|
||||||
apk.features = new String[] {"one", "two", "three" };
|
apk.features = new String[]{"one", "two", "three"};
|
||||||
long dateTimestamp = System.currentTimeMillis();
|
|
||||||
apk.added = new Date(dateTimestamp);
|
|
||||||
apk.hashType = "i'm a hash type";
|
apk.hashType = "i'm a hash type";
|
||||||
|
|
||||||
|
Date testTime = Utils.parseDate(Utils.formatTime(new Date(System.currentTimeMillis()), null), null);
|
||||||
|
apk.added = testTime;
|
||||||
|
|
||||||
ApkProvider.Helper.update(context, apk);
|
ApkProvider.Helper.update(context, apk);
|
||||||
|
|
||||||
// Should not have inserted anything else, just updated the already existing apk.
|
// Should not have inserted anything else, just updated the already existing apk.
|
||||||
@ -340,9 +351,10 @@ public class ApkProviderTest extends FDroidProviderTest {
|
|||||||
|
|
||||||
assertArrayEquals(new String[]{"KnownVuln", "Other anti feature"}, updatedApk.antiFeatures);
|
assertArrayEquals(new String[]{"KnownVuln", "Other anti feature"}, updatedApk.antiFeatures);
|
||||||
assertArrayEquals(new String[]{"one", "two", "three"}, updatedApk.features);
|
assertArrayEquals(new String[]{"one", "two", "three"}, updatedApk.features);
|
||||||
assertEquals(new Date(dateTimestamp).getYear(), updatedApk.added.getYear());
|
assertEquals(testTime.getYear(), updatedApk.added.getYear());
|
||||||
assertEquals(new Date(dateTimestamp).getMonth(), updatedApk.added.getMonth());
|
assertEquals(testTime.getYear(), updatedApk.added.getYear());
|
||||||
assertEquals(new Date(dateTimestamp).getDay(), updatedApk.added.getDay());
|
assertEquals(testTime.getMonth(), updatedApk.added.getMonth());
|
||||||
|
assertEquals(testTime.getDay(), updatedApk.added.getDay());
|
||||||
assertEquals("i'm a hash type", updatedApk.hashType);
|
assertEquals("i'm a hash type", updatedApk.hashType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,8 +393,8 @@ public class ApkProviderTest extends FDroidProviderTest {
|
|||||||
assertEquals("a hash type", apk.hashType);
|
assertEquals("a hash type", apk.hashType);
|
||||||
|
|
||||||
String[] projection = {
|
String[] projection = {
|
||||||
Cols.Package.PACKAGE_NAME,
|
Cols.Package.PACKAGE_NAME,
|
||||||
Cols.HASH,
|
Cols.HASH,
|
||||||
};
|
};
|
||||||
|
|
||||||
Apk apkLessFields = ApkProvider.Helper.findApkFromAnyRepo(context, "com.example", 11, null, projection);
|
Apk apkLessFields = ApkProvider.Helper.findApkFromAnyRepo(context, "com.example", 11, null, projection);
|
||||||
|
@ -11,6 +11,7 @@ import org.fdroid.fdroid.Preferences;
|
|||||||
import org.fdroid.fdroid.TestUtils;
|
import org.fdroid.fdroid.TestUtils;
|
||||||
import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols;
|
import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
@ -19,6 +20,7 @@ import org.robolectric.shadows.ShadowContentResolver;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import static org.fdroid.fdroid.Assert.assertContainsOnly;
|
import static org.fdroid.fdroid.Assert.assertContainsOnly;
|
||||||
import static org.fdroid.fdroid.Assert.assertResultCount;
|
import static org.fdroid.fdroid.Assert.assertResultCount;
|
||||||
@ -36,6 +38,13 @@ public class AppProviderTest extends FDroidProviderTest {
|
|||||||
|
|
||||||
private static final String[] PROJ = Cols.ALL;
|
private static final String[] PROJ = Cols.ALL;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setRandomTimeZone() {
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT-%d:%02d",
|
||||||
|
System.currentTimeMillis() % 12, System.currentTimeMillis() % 60)));
|
||||||
|
System.out.println("TIME ZONE for this test: " + TimeZone.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class);
|
TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class);
|
||||||
|
@ -30,6 +30,7 @@ import org.fdroid.fdroid.BuildConfig;
|
|||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
import org.fdroid.fdroid.Utils;
|
import org.fdroid.fdroid.Utils;
|
||||||
import org.fdroid.fdroid.data.Schema.RepoTable;
|
import org.fdroid.fdroid.data.Schema.RepoTable;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
@ -37,6 +38,7 @@ import org.robolectric.annotation.Config;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@ -48,6 +50,16 @@ public class RepoProviderTest extends FDroidProviderTest {
|
|||||||
|
|
||||||
private static final String[] COLS = RepoTable.Cols.ALL;
|
private static final String[] COLS = RepoTable.Cols.ALL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to random time zone to make sure that the dates are properly parsed.
|
||||||
|
*/
|
||||||
|
@BeforeClass
|
||||||
|
public static void setRandomTimeZone() {
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT-%d:%02d",
|
||||||
|
System.currentTimeMillis() % 12, System.currentTimeMillis() % 60)));
|
||||||
|
System.out.println("TIME ZONE for this test: " + TimeZone.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void countEnabledRepos() {
|
public void countEnabledRepos() {
|
||||||
|
|
||||||
@ -95,7 +107,7 @@ public class RepoProviderTest extends FDroidProviderTest {
|
|||||||
|
|
||||||
private Repo setLastUpdate(Repo repo, Date date) {
|
private Repo setLastUpdate(Repo repo, Date date) {
|
||||||
ContentValues values = new ContentValues(1);
|
ContentValues values = new ContentValues(1);
|
||||||
values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatDate(date, null));
|
values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatTime(date, null));
|
||||||
RepoProvider.Helper.update(context, repo, values);
|
RepoProvider.Helper.update(context, repo, values);
|
||||||
return RepoProvider.Helper.findByAddress(context, repo.address);
|
return RepoProvider.Helper.findByAddress(context, repo.address);
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import org.apache.commons.io.FileUtils;
|
|||||||
import org.fdroid.fdroid.BuildConfig;
|
import org.fdroid.fdroid.BuildConfig;
|
||||||
import org.fdroid.fdroid.mock.MockRepo;
|
import org.fdroid.fdroid.mock.MockRepo;
|
||||||
import org.fdroid.fdroid.mock.RepoDetails;
|
import org.fdroid.fdroid.mock.RepoDetails;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
@ -48,6 +49,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@ -63,6 +65,16 @@ public class RepoXMLHandlerTest {
|
|||||||
|
|
||||||
private static final String FAKE_SIGNING_CERT = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345"; // NOCHECKSTYLE LineLength
|
private static final String FAKE_SIGNING_CERT = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345"; // NOCHECKSTYLE LineLength
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to random time zone to make sure that the dates are properly parsed.
|
||||||
|
*/
|
||||||
|
@BeforeClass
|
||||||
|
public static void setRandomTimeZone() {
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT-%d:%02d",
|
||||||
|
System.currentTimeMillis() % 12, System.currentTimeMillis() % 60)));
|
||||||
|
System.out.println("TIME ZONE for this test: " + TimeZone.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExtendedPerms() throws IOException {
|
public void testExtendedPerms() throws IOException {
|
||||||
Repo expectedRepo = new Repo();
|
Repo expectedRepo = new Repo();
|
||||||
@ -129,6 +141,12 @@ public class RepoXMLHandlerTest {
|
|||||||
"org.gege.caldavsyncadapter",
|
"org.gege.caldavsyncadapter",
|
||||||
"info.guardianproject.checkey",
|
"info.guardianproject.checkey",
|
||||||
});
|
});
|
||||||
|
for (App app : actualDetails.apps) {
|
||||||
|
if ("org.mozilla.firefox".equals(app.packageName)) {
|
||||||
|
assertEquals(1411776000000L, app.added.getTime());
|
||||||
|
assertEquals(1411862400000L, app.lastUpdated.getTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
@ -897,6 +915,10 @@ public class RepoXMLHandlerTest {
|
|||||||
List<App> apps = actualDetails.apps;
|
List<App> apps = actualDetails.apps;
|
||||||
assertNotNull(apps);
|
assertNotNull(apps);
|
||||||
assertEquals(apps.size(), appCount);
|
assertEquals(apps.size(), appCount);
|
||||||
|
for (App app : apps) {
|
||||||
|
assertTrue("Added should have been set", app.added.getTime() > 0);
|
||||||
|
assertTrue("Last Updated should have been set", app.lastUpdated.getTime() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
List<Apk> apks = actualDetails.apks;
|
List<Apk> apks = actualDetails.apks;
|
||||||
assertNotNull(apks);
|
assertNotNull(apks);
|
||||||
|
File diff suppressed because one or more lines are too long
48
tools/check-string-maxlength.py
Executable file
48
tools/check-string-maxlength.py
Executable file
@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Remove extra translations
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
|
maxlengths = {
|
||||||
|
"menu_install": 20,
|
||||||
|
"menu_uninstall": 20,
|
||||||
|
"nearby_splash__find_people_button": 30,
|
||||||
|
"nearby_splash__request_permission": 30,
|
||||||
|
"update_all": 20,
|
||||||
|
"updates__hide_updateable_apps": 35,
|
||||||
|
"updates__show_updateable_apps": 35,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
resdir = os.path.join(os.path.dirname(__file__), '..', 'app', 'src', 'main', 'res')
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
for d in sorted(glob.glob(os.path.join(resdir, 'values-*'))):
|
||||||
|
locale = d.split('/')[-1][7:]
|
||||||
|
|
||||||
|
str_path = os.path.join(d, 'strings.xml')
|
||||||
|
if not os.path.exists(str_path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
with open(str_path, encoding='utf-8') as fp:
|
||||||
|
fulltext = fp.read()
|
||||||
|
|
||||||
|
tree = ElementTree.parse(str_path)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
for e in root.findall('.//string'):
|
||||||
|
|
||||||
|
if maxlengths.get(e.attrib['name']) is not None \
|
||||||
|
and len(e.text) > maxlengths.get(e.attrib['name']):
|
||||||
|
print(e.attrib['name'], locale, str(len(e.text)) + ':\t\t"' + e.text + '"')
|
||||||
|
|
||||||
|
if count > 0:
|
||||||
|
print("%d over-long strings found!" % count)
|
||||||
|
sys.exit(count)
|
||||||
|
|
82
tools/pick-complete-translations.py
Executable file
82
tools/pick-complete-translations.py
Executable file
@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
#
|
||||||
|
# cherry-pick complete translations from weblate
|
||||||
|
|
||||||
|
import git
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import requests
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def get_paths_tuple(locale):
|
||||||
|
return (
|
||||||
|
'metadata/%s/*.txt' % locale,
|
||||||
|
'metadata/%s/changelogs/*.txt' % locale,
|
||||||
|
'app/src/main/res/values-%s/strings.xml' % re.sub(r'-', r'-r', locale),
|
||||||
|
)
|
||||||
|
|
||||||
|
projectbasedir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
print(projectbasedir)
|
||||||
|
|
||||||
|
repo = git.Repo(projectbasedir)
|
||||||
|
weblate = repo.remotes.weblate
|
||||||
|
weblate.fetch()
|
||||||
|
upstream = repo.remotes.upstream
|
||||||
|
upstream.fetch()
|
||||||
|
|
||||||
|
url = 'https://hosted.weblate.org/exports/stats/f-droid/f-droid/?format=json'
|
||||||
|
r = requests.get(url)
|
||||||
|
r.raise_for_status()
|
||||||
|
app = r.json()
|
||||||
|
|
||||||
|
url = 'https://hosted.weblate.org/exports/stats/f-droid/f-droid-metadata/?format=json'
|
||||||
|
r = requests.get(url)
|
||||||
|
r.raise_for_status()
|
||||||
|
metadata = r.json()
|
||||||
|
|
||||||
|
|
||||||
|
#with open('f-droid-metadata.json') as fp:
|
||||||
|
# metadata = json.load(fp)
|
||||||
|
|
||||||
|
app_locales = dict()
|
||||||
|
metadata_locales = dict()
|
||||||
|
|
||||||
|
merge_locales = []
|
||||||
|
for locale in app:
|
||||||
|
app_locales[locale['code']] = locale
|
||||||
|
for locale in metadata:
|
||||||
|
metadata_locales[locale['code']] = locale
|
||||||
|
|
||||||
|
for locale in sorted(app_locales.keys(), reverse=True):
|
||||||
|
a = app_locales.get(locale)
|
||||||
|
m = metadata_locales.get(locale)
|
||||||
|
if a is not None and a['translated_percent'] == 100 and a['failing'] == 0 \
|
||||||
|
and m is not None and m['translated_percent'] == 100 and m['failing'] == 0:
|
||||||
|
print(locale)
|
||||||
|
merge_locales.append(locale)
|
||||||
|
|
||||||
|
if not merge_locales:
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if 'merge_weblate' in repo.heads:
|
||||||
|
merge_weblate = repo.heads['merge_weblate']
|
||||||
|
repo.create_tag('previous_merge_weblate', ref=merge_weblate,
|
||||||
|
message=('Automatically created by %s' % __file__))
|
||||||
|
else:
|
||||||
|
merge_weblate = repo.create_head('merge_weblate')
|
||||||
|
merge_weblate.set_commit(upstream.refs.master)
|
||||||
|
merge_weblate.checkout()
|
||||||
|
|
||||||
|
email_pattern = re.compile(r'by (.*?) <(.*)>$')
|
||||||
|
|
||||||
|
for locale in sorted(merge_locales):
|
||||||
|
commits = list(repo.iter_commits(
|
||||||
|
str(weblate.refs.master) + '...' + str(upstream.refs.master),
|
||||||
|
paths=get_paths_tuple(locale), max_count=10))
|
||||||
|
for commit in reversed(commits):
|
||||||
|
repo.git.cherry_pick(str(commit))
|
||||||
|
m = email_pattern.search(commit.summary)
|
||||||
|
if m:
|
||||||
|
email = m.group(1) + ' <' + m.group(2) + '>'
|
Loading…
x
Reference in New Issue
Block a user