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 #101 from zanata/ZNTA-930-filetype-init
Browse files Browse the repository at this point in the history
ZNTA-930 - zanata init can handle file type project
  • Loading branch information
Patrick Huang committed Mar 10, 2016
2 parents 9b67013 + 9ef5506 commit cb33e23
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 50 deletions.
Expand Up @@ -23,6 +23,8 @@
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.kohsuke.args4j.Option;
Expand All @@ -36,13 +38,23 @@
import org.zanata.client.commands.push.PushCommand;
import org.zanata.client.commands.push.PushOptions;
import org.zanata.client.commands.push.PushOptionsImpl;
import org.zanata.client.commands.push.RawPushCommand;
import org.zanata.client.commands.push.RawPushStrategy;
import org.zanata.common.DocumentType;
import org.zanata.rest.client.FileResourceClient;
import org.zanata.rest.client.RestClientFactory;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

import static org.zanata.client.commands.ConsoleInteractor.DisplayMode.Hint;
import static org.zanata.client.commands.ConsoleInteractor.DisplayMode.Question;
import static org.zanata.client.commands.ConsoleInteractor.DisplayMode.Warning;
import static org.zanata.client.commands.StringUtil.indent;
import static org.zanata.client.commands.ConsoleInteractorImpl.AnswerValidatorImpl.*;
import static org.zanata.common.ProjectType.File;
import static org.zanata.client.commands.Messages.get;

/**
Expand All @@ -60,12 +72,13 @@ class SourceConfigPrompt {
private final ConsoleInteractor console;
private final ConfigurableProjectOptions opts;
private final PushOptions pushOptions;
private final SrcDocsFinder
srcDocsFinder;
// includes and excludes in ConfigurableProjectOptions do not have symmetric
// setter/getter (set method accepts String but get method returns
// ImmutableList) therefore we have to keep instance variables here
private String includes;
private String excludes;
private PushCommand pushCommand;
private Set<String> docNames;

public SourceConfigPrompt(
Expand All @@ -83,13 +96,7 @@ public SourceConfigPrompt(
pushOptions.setKey(opts.getKey());
pushOptions.setLocaleMapList(opts.getLocaleMapList());

RestClientFactory clientFactory =
OptionsUtil.createClientFactoryWithoutVersionCheck(pushOptions);
pushCommand =
new PushCommand(pushOptions,
clientFactory.getCopyTransClient(),
clientFactory.getAsyncProcessClient(),
clientFactory);
srcDocsFinder = makeSrcDocFinder();
}

SourceConfigPrompt promptUser() throws Exception {
Expand Down Expand Up @@ -117,6 +124,21 @@ SourceConfigPrompt promptUser() throws Exception {
pushOptions.setSrcDir(srcDir);
pushOptions.setIncludes(includes);
pushOptions.setExcludes(excludes);


// if project type is file, we need to ask file type in order to find source documents
if (File.name().equalsIgnoreCase(pushOptions.getProjectType())) {

console.blankLine();
console.printfln(Question, get("project.file.type.question"));

// this answer is not persisted in zanata.xml so user will still need to type it when they do the actual push
console.printfln(Hint, PushOptionsImpl.fileTypeHelp);
console.printf(Question, get("file.type.prompt"));
String answer = console.expectAnyNotBlankAnswer();
((PushOptionsImpl) pushOptions).setFileTypes(answer);
}

console.blankLine();
docNames = findDocNames();
if (docNames.isEmpty()) {
Expand All @@ -140,13 +162,14 @@ SourceConfigPrompt promptUser() throws Exception {
return this;
}

@VisibleForTesting
protected RestClientFactory getClientFactory(PushOptions pushOptions) {
return OptionsUtil
.createClientFactoryWithoutVersionCheck(pushOptions);
}

private Set<String> findDocNames() throws IOException {
AbstractPushStrategy strategy = pushCommand.getStrategy(pushOptions);
return strategy.findDocNames(pushOptions.getSrcDir(),
pushOptions.getIncludes(), pushOptions.getExcludes(),
pushOptions.getDefaultExcludes(),
pushOptions.getCaseSensitive(),
pushOptions.getExcludeLocaleFilenames());
return srcDocsFinder.findSrcDocNames();
}

private void hintAdvancedConfigurations() {
Expand Down Expand Up @@ -191,4 +214,95 @@ public String getExcludes() {
public Set<String> getDocNames() {
return docNames;
}

private SrcDocsFinder makeSrcDocFinder() {
String projectType = pushOptions.getProjectType();
if (projectType.equalsIgnoreCase(File.name())) {
return new RawSrcDocsFinder(pushOptions);
} else {
return new OtherSrcDocsFinder(pushOptions);
}
}

interface SrcDocsFinder {
Set<String> findSrcDocNames();
}

class RawSrcDocsFinder implements SrcDocsFinder {

private final RawPushStrategy strategy;

RawSrcDocsFinder(PushOptions pushOptions) {
strategy = new RawPushStrategy();
strategy.setPushOptions(pushOptions);
}

@Override
public Set<String> findSrcDocNames() {
PushOptions opts = strategy.getOpts();
ImmutableList<String> extensions = filteredFileExtensions(opts);
return ImmutableSet.copyOf(strategy.getSrcFiles(
opts.getSrcDir(), opts.getIncludes(),
opts.getExcludes(), extensions,
opts.getDefaultExcludes(),
opts.getCaseSensitive()));
}

private ImmutableList<String> filteredFileExtensions(PushOptions opts) {
// mostly duplicated in RawPushCommand
RestClientFactory clientFactory = getClientFactory(opts);
RawPushCommand rawPushCommand =
new RawPushCommand(opts, clientFactory, console);
FileResourceClient client =
clientFactory.getFileResourceClient();
List<DocumentType> rawDocumentTypes = client.acceptedFileTypes();
Map<DocumentType, Set<String>> filteredDocTypes =
rawPushCommand.validateFileTypes(rawDocumentTypes,
opts.getFileTypes());

if (filteredDocTypes.isEmpty()) {
log.info("no valid types specified; nothing to do");
return ImmutableList.of();
}

ImmutableList.Builder<String> sourceFileExtensionsBuilder =
ImmutableList.builder();
for (Set<String> filteredSourceExtensions : filteredDocTypes
.values()) {
sourceFileExtensionsBuilder.addAll(filteredSourceExtensions);
}
return sourceFileExtensionsBuilder.build();
}
}

class OtherSrcDocsFinder implements SrcDocsFinder {
private final AbstractPushStrategy strategy;
private PushOptions opts;

OtherSrcDocsFinder(PushOptions pushOptions) {
opts = pushOptions;
RestClientFactory clientFactory = getClientFactory(pushOptions);
PushCommand pushCommand =
new PushCommand(pushOptions,
clientFactory.getCopyTransClient(),
clientFactory.getAsyncProcessClient(),
clientFactory);
strategy = pushCommand.getStrategy(pushOptions);
}

@Override
public Set<String> findSrcDocNames() {
try {
return strategy
.findDocNames(opts.getSrcDir(), opts.getIncludes(),
opts.getExcludes(),
opts.getDefaultExcludes(),
opts.getCaseSensitive(),
opts.getExcludeLocaleFilenames());
} catch (IOException e) {
throw Throwables.propagate(e);
}
}
}
}

Expand Up @@ -23,16 +23,20 @@
import java.io.File;
import java.util.Set;

import org.apache.commons.io.FilenameUtils;
import org.zanata.client.commands.ConfigurableProjectOptions;
import org.zanata.client.commands.ConsoleInteractor;
import org.zanata.client.commands.OptionsUtil;
import org.zanata.client.commands.pull.PullCommand;
import org.zanata.client.commands.QualifiedSrcDocName;
import org.zanata.client.commands.TransFileResolver;
import org.zanata.client.commands.UnqualifiedSrcDocName;
import org.zanata.client.commands.pull.PullOptions;
import org.zanata.client.commands.pull.PullOptionsImpl;
import org.zanata.client.commands.pull.PullStrategy;
import org.zanata.client.config.LocaleList;
import org.zanata.client.config.LocaleMapping;
import org.zanata.rest.client.RestClientFactory;
import org.zanata.common.ProjectType;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;

Expand All @@ -55,7 +59,8 @@ class TransConfigPrompt {
private final ConfigurableProjectOptions opts;
private final Set<String> srcFilesSample;
private final PullOptionsImpl pullOptions;
private final PullCommand pullCommand;
private final TransFilePathFinder
transFilePathFinder;
private int remainingFileNumber;

public TransConfigPrompt(ConsoleInteractor console,
Expand All @@ -74,10 +79,7 @@ public TransConfigPrompt(ConsoleInteractor console,
pullOptions.setProjectType(opts.getProjectType());
pullOptions.setLocaleMapList(opts.getLocaleMapList());

RestClientFactory clientFactory =
OptionsUtil.createClientFactoryWithoutVersionCheck(opts);
pullCommand = new PullCommand(pullOptions,
clientFactory);
transFilePathFinder = makeTransFilePathFinder(pullOptions);
}

TransConfigPrompt promptUser() throws Exception {
Expand All @@ -86,12 +88,11 @@ TransConfigPrompt promptUser() throws Exception {
File transDir = new File(localTransDir);
pullOptions.setTransDir(transDir);

final PullStrategy strategy = pullCommand.createStrategy(pullOptions);
LocaleList localeMapList = pullOptions.getLocaleMapList();
LocaleMapping localeMapping = getSampleLocaleMapping(localeMapList);

Iterable<String> transFiles = Iterables.transform(srcFilesSample,
new ToTransFileNameFunction(strategy, localeMapping));
new ToTransFileNameFunction(transFilePathFinder, localeMapping));
console.printfln(Hint, get("trans.doc.preview"), localeMapping.getLocale());
for (String transFile : transFiles) {
console.printfln("%s%s", indent(8), transFile);
Expand All @@ -110,6 +111,14 @@ TransConfigPrompt promptUser() throws Exception {
return this;
}

private TransFilePathFinder makeTransFilePathFinder(PullOptions opts) {
if (ProjectType.File.name().equalsIgnoreCase(opts.getProjectType())) {
return new RawTransFilePathFinder(opts);
} else {
return new OtherTransFilePathFinder(opts);
}
}

private static LocaleMapping
getSampleLocaleMapping(LocaleList localeMapList) {
LocaleMapping localeMapping;
Expand All @@ -123,19 +132,61 @@ TransConfigPrompt promptUser() throws Exception {

private static class ToTransFileNameFunction
implements Function<String, String> {
private final PullStrategy strategy;
private final TransFilePathFinder transFilePathFinder;
private final LocaleMapping localeMapping;

public ToTransFileNameFunction(PullStrategy strategy,
public ToTransFileNameFunction(TransFilePathFinder transFilePathFinder,
LocaleMapping localeMapping) {
this.strategy = strategy;
this.transFilePathFinder = transFilePathFinder;
this.localeMapping = localeMapping;
}

@Override
public String apply(String input) {
return strategy.getTransFileToWrite(input, localeMapping).getPath();
return transFilePathFinder.getTransFileToWrite(input, localeMapping);

}
}

interface TransFilePathFinder {
String getTransFileToWrite(String srcDoc, LocaleMapping localeMapping);
}

static class RawTransFilePathFinder implements TransFilePathFinder {
private final TransFileResolver transFileResolver;

RawTransFilePathFinder(PullOptions opts) {
transFileResolver = new TransFileResolver(opts);
}

@Override
public String getTransFileToWrite(String srcDoc,
LocaleMapping localeMapping) {
String targetFileExt = FilenameUtils
.getExtension(srcDoc);

Optional<String> translationFileExtension =
Optional.fromNullable(targetFileExt);
File file = transFileResolver.resolveTransFile(
QualifiedSrcDocName.from(srcDoc),
localeMapping, translationFileExtension);
return file.getPath();
}
}

static class OtherTransFilePathFinder implements TransFilePathFinder {
private final TransFileResolver transFileResolver;

OtherTransFilePathFinder(PullOptions opts) {
this.transFileResolver = new TransFileResolver(opts);
}

@Override
public String getTransFileToWrite(String srcDoc,
LocaleMapping localeMapping) {
File transFile = transFileResolver.getTransFile(
UnqualifiedSrcDocName.from(srcDoc), localeMapping);
return transFile.getPath();
}
}
}
Expand Up @@ -189,7 +189,7 @@ public ImmutableList<String> getFileTypes() {
return fileTypes;
}

private static final String fileTypeHelp = "File types to locate and transmit to the server. \n" +
public static final String fileTypeHelp = "File types to locate and transmit to the server. \n" +
"Default file extension will be used unless it is being specified. \n" +
"Pattern: TYPE[extension;extension],TYPE[extension] \n" +
"Supported types: \n" +
Expand All @@ -206,7 +206,7 @@ public ImmutableList<String> getFileTypes() {
"\t PROPERTIES[properties] \n" +
"\t PROPERTIES_UTF8[properties] \n" +
"\t XLIFF[xml] \n" +
"Usage --file-types \"XML_DOCUMENT_TYPE_DEFINITION,IDML[txt]\"";
"Usage --file-types \"XML_DOCUMENT_TYPE_DEFINITION,PLAIN_TEXT[md;txt]\"";

@Option(name = "--file-types", metaVar = "TYPES",
usage = fileTypeHelp)
Expand Down
Expand Up @@ -103,8 +103,7 @@ public RawPushCommand(PushOptions opts, RestClientFactory clientFactory) {
consoleInteractor = new ConsoleInteractorImpl(opts);
}

@VisibleForTesting
protected RawPushCommand(PushOptions opts, RestClientFactory clientFactory,
public RawPushCommand(PushOptions opts, RestClientFactory clientFactory,
ConsoleInteractor console) {
super(opts, clientFactory);
client = getClientFactory().getFileResourceClient();
Expand Down Expand Up @@ -188,7 +187,7 @@ private void validateInputFileType(String inputFileType,
* @param acceptedTypes
* @param inputFileTypes
*/
private Map<DocumentType, Set<String>> validateFileTypes(
public Map<DocumentType, Set<String>> validateFileTypes(
List<DocumentType> acceptedTypes, List<String> inputFileTypes) {

Map<DocumentType, Set<String>> filteredFileTypes = new HashMap<>();
Expand Down
2 changes: 2 additions & 0 deletions zanata-client-commands/src/main/resources/prompts.properties
Expand Up @@ -43,6 +43,8 @@ includes.prompt=Includes (leave blank if not applicable):
excludes.question=Do you want to define any Excludes?
excludes.usage= - Wildcard pattern to exclude files and directories. Defined it as "configuration.properties,build.properties".
excludes.prompt=Excludes (leave blank if not applicable):
project.file.type.question=What file types do you want to use?
file.type.prompt=Please enter file types in comma separated format (e.g. XML_DOCUMENT_TYPE_DEFINITION,PLAIN_TEXT[md;txt]):
no.source.doc.found=No source documents found.
found.source.docs=Found source documents:
source.doc.confirm.yes.no=Continue with these source document settings (y/n)?
Expand Down

0 comments on commit cb33e23

Please sign in to comment.