Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
Merge pull request #63 from zanata/min-doc-percent
Browse files Browse the repository at this point in the history
rhbz1215274 - Min doc percent
  • Loading branch information
Patrick Huang committed May 27, 2015
2 parents 946c671 + a0cd169 commit d13462f
Show file tree
Hide file tree
Showing 13 changed files with 658 additions and 131 deletions.
Expand Up @@ -47,7 +47,7 @@ public void testDisableSSLCertOption() {
String project = "iok";
String version = "6.4";
client.processArgs(command, "--url", url, "--project", project,
"--project-version", version, "--disable-ssl-cert");
"--project-version", version, "--disable-ssl-cert", "--details");
}

@Test
Expand Down
Expand Up @@ -49,9 +49,9 @@ public interface BasicOptions {

boolean isQuietSet();

public boolean isInteractiveMode();
boolean isInteractiveMode();

public void setInteractiveMode(boolean interactiveMode);
void setInteractiveMode(boolean interactiveMode);

/**
* Used to generate the command line interface and its usage help. This name
Expand All @@ -60,17 +60,17 @@ public interface BasicOptions {
*
* @return
*/
public String getCommandName();
String getCommandName();

/**
* Used to generate CLI usage help. This description should preferably match
* the Maven Mojo's Javadoc description.
*
* @return
*/
public String getCommandDescription();
String getCommandDescription();

public @Nonnull List<CommandHook> getCommandHooks();
@Nonnull List<CommandHook> getCommandHooks();

public void setCommandHooks(@Nonnull List<CommandHook> commandHooks);
void setCommandHooks(@Nonnull List<CommandHook> commandHooks);
}
Expand Up @@ -18,51 +18,50 @@ public interface ConfigurableOptions extends BasicOptions {
/**
* API key for accessing the REST API. Defaults to the value in zanata.ini.
*/
public String getKey();
String getKey();

public void setKey(String key);
void setKey(String key);

/**
* Base URL for the server. Defaults to the value in zanata.xml.
*/
public URL getUrl();
URL getUrl();

public void setUrl(URL url);
void setUrl(URL url);

/**
* Client configuration file.
*/
public File getUserConfig();
File getUserConfig();

public void setUserConfig(File userConfig);
void setUserConfig(File userConfig);

/**
* Username for accessing the REST API. Defaults to the value in zanata.ini.
*/
public String getUsername();
String getUsername();

public void setUsername(String username);
void setUsername(String username);

/**
* Enable HTTP message logging.
*/
public boolean getLogHttp();
boolean getLogHttp();

public void setLogHttp(boolean traceLogging);
void setLogHttp(boolean traceLogging);

/**
* Disable SSL certificate verification when connecting to Zanata host by
* https.
*/
boolean isDisableSSLCert();

public
void setDisableSSLCert(boolean disableSSLCert);
void setDisableSSLCert(boolean disableSSLCert);

/**
* Use to disable check for presence of username and API key before running command.
*
* @return true if this command should fail when username or API key is absent.
*/
public boolean isAuthRequired();
boolean isAuthRequired();
}
Expand Up @@ -28,24 +28,33 @@
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zanata.client.commands.pull.PullOptions;
import org.zanata.client.config.LocaleList;
import org.zanata.client.config.LocaleMapping;
import org.zanata.client.etag.ETagCache;
import org.zanata.client.etag.ETagCacheReaderWriter;
import org.zanata.client.exceptions.ConfigException;
import org.zanata.common.LocaleId;
import org.zanata.rest.client.RestClientFactory;
import org.zanata.rest.client.SourceDocResourceClient;
import org.zanata.rest.client.StatisticsResourceClient;
import org.zanata.rest.client.TransDocResourceClient;
import org.zanata.rest.dto.resource.Resource;
import org.zanata.rest.dto.resource.ResourceMeta;
import org.zanata.rest.dto.resource.TranslationsResource;
import org.zanata.rest.dto.stats.ContainerTranslationStatistics;
import org.zanata.rest.dto.stats.TranslationStatistics;
import org.zanata.util.PathUtil;

import static org.zanata.client.commands.ConsoleInteractor.DisplayMode.Question;
Expand All @@ -67,6 +76,7 @@ public abstract class PushPullCommand<O extends PushPullOptions> extends
private String modulePrefix;
protected SourceDocResourceClient sourceDocResourceClient;
protected TransDocResourceClient transDocResourceClient;
protected final StatisticsResourceClient statsClient;

public PushPullCommand(O opts, RestClientFactory clientFactory) {
super(opts, clientFactory);
Expand All @@ -80,6 +90,7 @@ public PushPullCommand(O opts, RestClientFactory clientFactory) {
transDocResourceClient =
getClientFactory().getTransDocResourceClient(opts.getProj(),
opts.getProjectVersion());
statsClient = getClientFactory().getStatisticsClient();
}

public PushPullCommand(O opts) {
Expand Down Expand Up @@ -241,4 +252,125 @@ protected void storeETagCache() {
}
}

protected Map<String, Map<LocaleId, TranslatedPercent>> getDocsTranslatedPercent(
LocaleList locales) {
ContainerTranslationStatistics statistics =
getDetailStatisticsForProjectVersion(locales);
List<ContainerTranslationStatistics> statsPerDoc =
statistics.getDetailedStats();
ImmutableMap.Builder<String, Map<LocaleId, TranslatedPercent>> docIdToStatsBuilder =
ImmutableMap.builder();
for (ContainerTranslationStatistics docStats : statsPerDoc) {
String docId = docStats.getId();
List<TranslationStatistics> statsPerLocale = docStats.getStats();
ImmutableMap.Builder<LocaleId, TranslatedPercent> localeToStatsBuilder =
ImmutableMap.builder();

for (TranslationStatistics statsForSingleLocale : statsPerLocale) {
// TODO server statistics API should return locale with alias
TranslatedPercent translatedPercent =
new TranslatedPercent(statsForSingleLocale.getTotal(),
statsForSingleLocale.getTranslatedOnly(),
statsForSingleLocale.getApproved());

localeToStatsBuilder.put(
new LocaleId(statsForSingleLocale.getLocale()),
translatedPercent);
}
Map<LocaleId, TranslatedPercent> localeStats =
localeToStatsBuilder.build();
docIdToStatsBuilder.put(docId, localeStats);
}
return docIdToStatsBuilder.build();
}

@VisibleForTesting
protected ContainerTranslationStatistics getDetailStatisticsForProjectVersion(
LocaleList locales) {
String[] localesOnServer = new String[locales.size()];
for (int i = 0; i < locales.size(); i++) {
localesOnServer[i] = locales.get(i).getLocale();
}
return statsClient
.getStatistics(getOpts().getProj(),
getOpts().getProjectVersion(), true, false, localesOnServer);
}

/**
* this stats map will have docId as key, the value is another map with
* localeId as key and translated percent as value.
* It's optional if we require statistics to determine which file to pull.
* In cases where statistics is not required,
* i.e. pull source only or minimum percent is set to 0, this will be
* Optional.absence().
*
* @param pullTarget whether we need to pull translation target
* @param locales
* @return either detailed document statistics or optional.absence()
*/
protected Optional<Map<String, Map<LocaleId, TranslatedPercent>>> prepareStatsIfApplicable(
boolean pullTarget, LocaleList locales) {

Optional<Map<String, Map<LocaleId, TranslatedPercent>>> optionalStats =
Optional.absent();
if (needToGetStatistics(pullTarget)) {
optionalStats = Optional.of(getDocsTranslatedPercent(locales));
}
return optionalStats;
}

protected boolean needToGetStatistics(boolean pullTarget) {
return pullTarget && getOpts() instanceof PullOptions &&
((PullOptions) getOpts()).getMinDocPercent() > 0;
}

protected boolean shouldPullThisLocale(
Optional<Map<String, Map<LocaleId, TranslatedPercent>>> optionalStats,
String localDocName, LocaleId serverLocale) {
int minDocPercent = ((PullOptions) getOpts()).getMinDocPercent();
if (log.isDebugEnabled() && optionalStats.isPresent()) {
log.debug("{} for locale {} is translated {}%", localDocName,
serverLocale, optionalStats.get()
.get(localDocName).get(serverLocale)
.getTranslatedPercent());
}
return !optionalStats.isPresent()
|| optionalStats.get().get(localDocName).get(serverLocale)
.isAboveThreshold(minDocPercent);
}

protected static class TranslatedPercent {
private final double translatedPercent;
private final long total;
private final long translated;
private final long approved;

public TranslatedPercent(long total, long translated, long approved) {
this.total = total;
this.translated = translated;
this.approved = approved;
if (total == 0) {
// in some case the document has no content, we want to pull the
// translation file regardless
translatedPercent = 100;
} else {
translatedPercent = (translated + approved) * 100.0 / total;

}
}

public boolean isAboveThreshold(int minimumPercent) {
// if minimum percent is 100, we will compare exact number so that
// rounding issue won't affect the result
if (minimumPercent == 100) {
return total == translated + approved;
} else {
return translatedPercent >= minimumPercent;
}
}

public double getTranslatedPercent() {
return translatedPercent;
}
}
}
Expand Up @@ -55,15 +55,15 @@ public interface PushPullOptions extends ConfigurableProjectOptions {

File getTransDir();

public String getFromDoc();
String getFromDoc();

/**
* This name should represent the exact parameter as it would be entered on
* the command line, and include any space or operators that would link the
* parameter to the argument. This is so that the argument can be appended
* directly to the parameter name.
*/
public String buildFromDocArgument(String argValue);
String buildFromDocArgument(String argValue);

boolean getEnableModules();

Expand Down

0 comments on commit d13462f

Please sign in to comment.