169362b5b63875987b050354b6852db76cb799d8cGeorge Mount/*
269362b5b63875987b050354b6852db76cb799d8cGeorge Mount * Copyright (C) 2015 The Android Open Source Project
369362b5b63875987b050354b6852db76cb799d8cGeorge Mount *
469362b5b63875987b050354b6852db76cb799d8cGeorge Mount * Licensed under the Apache License, Version 2.0 (the "License");
569362b5b63875987b050354b6852db76cb799d8cGeorge Mount * you may not use this file except in compliance with the License.
669362b5b63875987b050354b6852db76cb799d8cGeorge Mount * You may obtain a copy of the License at
769362b5b63875987b050354b6852db76cb799d8cGeorge Mount *
869362b5b63875987b050354b6852db76cb799d8cGeorge Mount *      http://www.apache.org/licenses/LICENSE-2.0
969362b5b63875987b050354b6852db76cb799d8cGeorge Mount *
1069362b5b63875987b050354b6852db76cb799d8cGeorge Mount * Unless required by applicable law or agreed to in writing, software
1169362b5b63875987b050354b6852db76cb799d8cGeorge Mount * distributed under the License is distributed on an "AS IS" BASIS,
1269362b5b63875987b050354b6852db76cb799d8cGeorge Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1369362b5b63875987b050354b6852db76cb799d8cGeorge Mount * See the License for the specific language governing permissions and
1469362b5b63875987b050354b6852db76cb799d8cGeorge Mount * limitations under the License.
1569362b5b63875987b050354b6852db76cb799d8cGeorge Mount */
16fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool;
1769362b5b63875987b050354b6852db76cb799d8cGeorge Mount
1869362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport org.apache.commons.io.FileUtils;
1969362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport org.apache.commons.io.IOUtils;
2069362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport org.w3c.dom.Document;
21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount
2230cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mountimport android.databinding.tool.store.ResourceBundle.LayoutFileBundle;
2330cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mountimport android.databinding.tool.util.GenerationalClassUtil;
24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.writer.JavaFileWriter;
2569362b5b63875987b050354b6852db76cb799d8cGeorge Mount
2669362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport java.io.File;
2769362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport java.io.FileWriter;
2869362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport java.io.FilenameFilter;
2969362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport java.io.IOException;
3069362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport java.util.ArrayList;
3130cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mountimport java.util.HashMap;
3230cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mountimport java.util.List;
3330cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mountimport java.util.Map;
3469362b5b63875987b050354b6852db76cb799d8cGeorge Mount
3569362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport javax.xml.parsers.DocumentBuilder;
3669362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport javax.xml.parsers.DocumentBuilderFactory;
3769362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport javax.xml.xpath.XPath;
3869362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport javax.xml.xpath.XPathConstants;
3969362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport javax.xml.xpath.XPathExpressionException;
4069362b5b63875987b050354b6852db76cb799d8cGeorge Mountimport javax.xml.xpath.XPathFactory;
4169362b5b63875987b050354b6852db76cb799d8cGeorge Mount
4269362b5b63875987b050354b6852db76cb799d8cGeorge Mount/**
4369362b5b63875987b050354b6852db76cb799d8cGeorge Mount * This class is used by make to copy resources to an intermediate directory and start processing
4469362b5b63875987b050354b6852db76cb799d8cGeorge Mount * them. When aapt takes over, this can be easily extracted to a short script.
4569362b5b63875987b050354b6852db76cb799d8cGeorge Mount */
4669362b5b63875987b050354b6852db76cb799d8cGeorge Mountpublic class MakeCopy {
4769362b5b63875987b050354b6852db76cb799d8cGeorge Mount    private static final int MANIFEST_INDEX = 0;
48ee7586713d68806b556a425cbebf007a56261ff3Yigit Boyar    private static final int SRC_INDEX = 1;
49ee7586713d68806b556a425cbebf007a56261ff3Yigit Boyar    private static final int XML_INDEX = 2;
50ee7586713d68806b556a425cbebf007a56261ff3Yigit Boyar    private static final int RES_OUT_INDEX = 3;
51ee7586713d68806b556a425cbebf007a56261ff3Yigit Boyar    private static final int RES_IN_INDEX = 4;
5269362b5b63875987b050354b6852db76cb799d8cGeorge Mount
53fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount    private static final String APP_SUBPATH = LayoutXmlProcessor.RESOURCE_BUNDLE_PACKAGE
5469362b5b63875987b050354b6852db76cb799d8cGeorge Mount            .replace('.', File.separatorChar);
5569362b5b63875987b050354b6852db76cb799d8cGeorge Mount    private static final FilenameFilter LAYOUT_DIR_FILTER = new FilenameFilter() {
5669362b5b63875987b050354b6852db76cb799d8cGeorge Mount        @Override
5769362b5b63875987b050354b6852db76cb799d8cGeorge Mount        public boolean accept(File dir, String name) {
5869362b5b63875987b050354b6852db76cb799d8cGeorge Mount            return name.toLowerCase().startsWith("layout");
5969362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
6069362b5b63875987b050354b6852db76cb799d8cGeorge Mount    };
6169362b5b63875987b050354b6852db76cb799d8cGeorge Mount
6269362b5b63875987b050354b6852db76cb799d8cGeorge Mount    private static final FilenameFilter XML_FILENAME_FILTER = new FilenameFilter() {
6369362b5b63875987b050354b6852db76cb799d8cGeorge Mount        @Override
6469362b5b63875987b050354b6852db76cb799d8cGeorge Mount        public boolean accept(File dir, String name) {
6569362b5b63875987b050354b6852db76cb799d8cGeorge Mount            return name.toLowerCase().endsWith(".xml");
6669362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
6769362b5b63875987b050354b6852db76cb799d8cGeorge Mount    };
6869362b5b63875987b050354b6852db76cb799d8cGeorge Mount
6969362b5b63875987b050354b6852db76cb799d8cGeorge Mount    public static void main(String[] args) {
70ee7586713d68806b556a425cbebf007a56261ff3Yigit Boyar        if (args.length < 5) {
7130cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount            System.out.println("required parameters: [-l] manifest adk-dir src-out-dir xml-out-dir " +
7269362b5b63875987b050354b6852db76cb799d8cGeorge Mount                            "res-out-dir res-in-dir...");
7369362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.out.println("Creates an android data binding class and copies resources from");
7469362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.out.println("res-source to res-target and modifies binding layout files");
7569362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.out.println("in res-target. Binding data is extracted into XML files");
7669362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.out.println("and placed in xml-out-dir.");
7730cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount            System.out.println("  -l          indicates that this is a library");
7869362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.out.println("  manifest    path to AndroidManifest.xml file");
7969362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.out.println("  src-out-dir path to where generated source goes");
8069362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.out.println("  xml-out-dir path to where generated binding XML goes");
8169362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.out.println("  res-out-dir path to the where modified resources should go");
8269362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.out.println("  res-in-dir  path to source resources \"res\" directory. One" +
8369362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    " or more are allowed.");
8469362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.exit(1);
8569362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
8630cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount        final boolean isLibrary = args[0].equals("-l");
8730cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount        final int indexOffset = isLibrary ? 1 : 0;
8869362b5b63875987b050354b6852db76cb799d8cGeorge Mount        final String applicationPackage;
8969362b5b63875987b050354b6852db76cb799d8cGeorge Mount        final int minSdk;
9030cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount        final Document androidManifest = readAndroidManifest(
9130cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount                new File(args[MANIFEST_INDEX + indexOffset]));
9269362b5b63875987b050354b6852db76cb799d8cGeorge Mount        try {
9369362b5b63875987b050354b6852db76cb799d8cGeorge Mount            final XPathFactory xPathFactory = XPathFactory.newInstance();
9469362b5b63875987b050354b6852db76cb799d8cGeorge Mount            final XPath xPath = xPathFactory.newXPath();
9569362b5b63875987b050354b6852db76cb799d8cGeorge Mount            applicationPackage = xPath.evaluate("string(/manifest/@package)", androidManifest);
9669362b5b63875987b050354b6852db76cb799d8cGeorge Mount            final Double minSdkNumber = (Double) xPath.evaluate(
9769362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    "number(/manifest/uses-sdk/@android:minSdkVersion)", androidManifest,
9869362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    XPathConstants.NUMBER);
9969362b5b63875987b050354b6852db76cb799d8cGeorge Mount            minSdk = minSdkNumber == null ? 1 : minSdkNumber.intValue();
10069362b5b63875987b050354b6852db76cb799d8cGeorge Mount        } catch (XPathExpressionException e) {
10169362b5b63875987b050354b6852db76cb799d8cGeorge Mount            e.printStackTrace();
10269362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.exit(6);
10369362b5b63875987b050354b6852db76cb799d8cGeorge Mount            return;
10469362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
10530cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount        final File srcDir = new File(args[SRC_INDEX + indexOffset], APP_SUBPATH);
10669362b5b63875987b050354b6852db76cb799d8cGeorge Mount        if (!makeTargetDir(srcDir)) {
10769362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.err.println("Could not create source directory " + srcDir);
10869362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.exit(2);
10969362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
11030cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount        final File resTarget = new File(args[RES_OUT_INDEX + indexOffset]);
11169362b5b63875987b050354b6852db76cb799d8cGeorge Mount        if (!makeTargetDir(resTarget)) {
11269362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.err.println("Could not create resource directory: " + resTarget);
11369362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.exit(4);
11469362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
11530cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount        final File xmlDir = new File(args[XML_INDEX + indexOffset]);
11669362b5b63875987b050354b6852db76cb799d8cGeorge Mount        if (!makeTargetDir(xmlDir)) {
11769362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.err.println("Could not create xml output directory: " + xmlDir);
11869362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.exit(5);
11969362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
12069362b5b63875987b050354b6852db76cb799d8cGeorge Mount        System.out.println("Application Package: " + applicationPackage);
12169362b5b63875987b050354b6852db76cb799d8cGeorge Mount        System.out.println("Minimum SDK: " + minSdk);
12269362b5b63875987b050354b6852db76cb799d8cGeorge Mount        System.out.println("Target Resources: " + resTarget.getAbsolutePath());
12369362b5b63875987b050354b6852db76cb799d8cGeorge Mount        System.out.println("Target Source Dir: " + srcDir.getAbsolutePath());
12469362b5b63875987b050354b6852db76cb799d8cGeorge Mount        System.out.println("Target XML Dir: " + xmlDir.getAbsolutePath());
12530cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount        System.out.println("Library? " + isLibrary);
12669362b5b63875987b050354b6852db76cb799d8cGeorge Mount
12769362b5b63875987b050354b6852db76cb799d8cGeorge Mount        boolean foundSomeResources = false;
12830cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount        for (int i = RES_IN_INDEX + indexOffset; i < args.length; i++) {
12969362b5b63875987b050354b6852db76cb799d8cGeorge Mount            final File resDir = new File(args[i]);
13069362b5b63875987b050354b6852db76cb799d8cGeorge Mount            if (!resDir.exists()) {
13130cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount                System.out.println("Could not find resource directory: " + resDir);
13269362b5b63875987b050354b6852db76cb799d8cGeorge Mount            } else {
13369362b5b63875987b050354b6852db76cb799d8cGeorge Mount                System.out.println("Source Resources: " + resDir.getAbsolutePath());
13469362b5b63875987b050354b6852db76cb799d8cGeorge Mount                try {
13569362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    FileUtils.copyDirectory(resDir, resTarget);
13669362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    addFromFile(resDir, resTarget);
13769362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    foundSomeResources = true;
13869362b5b63875987b050354b6852db76cb799d8cGeorge Mount                } catch (IOException e) {
13969362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    System.err.println("Could not copy resources from " + resDir + " to " + resTarget +
14069362b5b63875987b050354b6852db76cb799d8cGeorge Mount                            ": " + e.getLocalizedMessage());
14169362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    System.exit(3);
14269362b5b63875987b050354b6852db76cb799d8cGeorge Mount                }
14369362b5b63875987b050354b6852db76cb799d8cGeorge Mount            }
14469362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
14569362b5b63875987b050354b6852db76cb799d8cGeorge Mount
14669362b5b63875987b050354b6852db76cb799d8cGeorge Mount        if (!foundSomeResources) {
14769362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.err.println("No resource directories were found.");
14869362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.exit(7);
14969362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
150ee7586713d68806b556a425cbebf007a56261ff3Yigit Boyar        processLayoutFiles(applicationPackage, resTarget, srcDir, xmlDir, minSdk,
15169362b5b63875987b050354b6852db76cb799d8cGeorge Mount                isLibrary);
15269362b5b63875987b050354b6852db76cb799d8cGeorge Mount    }
15369362b5b63875987b050354b6852db76cb799d8cGeorge Mount
15469362b5b63875987b050354b6852db76cb799d8cGeorge Mount    private static Document readAndroidManifest(File manifest) {
15569362b5b63875987b050354b6852db76cb799d8cGeorge Mount        try {
15669362b5b63875987b050354b6852db76cb799d8cGeorge Mount            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
15769362b5b63875987b050354b6852db76cb799d8cGeorge Mount            DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
15869362b5b63875987b050354b6852db76cb799d8cGeorge Mount            return documentBuilder.parse(manifest);
15969362b5b63875987b050354b6852db76cb799d8cGeorge Mount        } catch (Exception e) {
16069362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.err.println("Could not load Android Manifest from " +
16169362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    manifest.getAbsolutePath() + ": " + e.getLocalizedMessage());
16269362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.exit(8);
16369362b5b63875987b050354b6852db76cb799d8cGeorge Mount            return null;
16469362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
16569362b5b63875987b050354b6852db76cb799d8cGeorge Mount    }
16669362b5b63875987b050354b6852db76cb799d8cGeorge Mount
16769362b5b63875987b050354b6852db76cb799d8cGeorge Mount    private static void processLayoutFiles(String applicationPackage, File resTarget, File srcDir,
168ee7586713d68806b556a425cbebf007a56261ff3Yigit Boyar            File xmlDir, int minSdk, boolean isLibrary) {
16969362b5b63875987b050354b6852db76cb799d8cGeorge Mount        ArrayList<File> resourceFolders = new ArrayList<File>();
17069362b5b63875987b050354b6852db76cb799d8cGeorge Mount        resourceFolders.add(resTarget);
17169362b5b63875987b050354b6852db76cb799d8cGeorge Mount        MakeFileWriter makeFileWriter = new MakeFileWriter(srcDir);
17269362b5b63875987b050354b6852db76cb799d8cGeorge Mount        LayoutXmlProcessor xmlProcessor = new LayoutXmlProcessor(applicationPackage,
17369362b5b63875987b050354b6852db76cb799d8cGeorge Mount                resourceFolders, makeFileWriter, minSdk, isLibrary);
17469362b5b63875987b050354b6852db76cb799d8cGeorge Mount        try {
1754d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount            xmlProcessor.processResources(minSdk);
176be83770af82294c1841eef414513653646b88dc6Yigit Boyar            xmlProcessor.writeLayoutInfoFiles(xmlDir);
177b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            // TODO Looks like make does not support excluding from libs ?
178b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            xmlProcessor.writeInfoClass(null, xmlDir, null);
17930cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount            Map<String, List<LayoutFileBundle>> bundles =
18030cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount                    xmlProcessor.getResourceBundle().getLayoutBundles();
18130cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount            if (isLibrary) {
18230cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount                for (String name : bundles.keySet()) {
18330cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount                    LayoutFileBundle layoutFileBundle = bundles.get(name).get(0);
18430cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount                    String pkgName = layoutFileBundle.getBindingClassPackage().replace('.', '/');
18530cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount                    System.err.println(pkgName + '/' + layoutFileBundle.getBindingClassName() +
18630cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount                        ".class");
18730cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount                }
18830cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount            }
18969362b5b63875987b050354b6852db76cb799d8cGeorge Mount            if (makeFileWriter.getErrorCount() > 0) {
19069362b5b63875987b050354b6852db76cb799d8cGeorge Mount                System.exit(9);
19169362b5b63875987b050354b6852db76cb799d8cGeorge Mount            }
19269362b5b63875987b050354b6852db76cb799d8cGeorge Mount        } catch (Exception e) {
19369362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.err.println("Error processing layout files: " + e.getLocalizedMessage());
19469362b5b63875987b050354b6852db76cb799d8cGeorge Mount            System.exit(10);
19569362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
19669362b5b63875987b050354b6852db76cb799d8cGeorge Mount    }
19769362b5b63875987b050354b6852db76cb799d8cGeorge Mount
19869362b5b63875987b050354b6852db76cb799d8cGeorge Mount    private static void addFromFile(File resDir, File resTarget) {
19969362b5b63875987b050354b6852db76cb799d8cGeorge Mount        for (File layoutDir : resDir.listFiles(LAYOUT_DIR_FILTER)) {
20069362b5b63875987b050354b6852db76cb799d8cGeorge Mount            if (layoutDir.isDirectory()) {
20169362b5b63875987b050354b6852db76cb799d8cGeorge Mount                File targetDir = new File(resTarget, layoutDir.getName());
20269362b5b63875987b050354b6852db76cb799d8cGeorge Mount                for (File layoutFile : layoutDir.listFiles(XML_FILENAME_FILTER)) {
20369362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    File targetFile = new File(targetDir, layoutFile.getName());
20469362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    FileWriter appender = null;
20569362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    try {
20669362b5b63875987b050354b6852db76cb799d8cGeorge Mount                        appender = new FileWriter(targetFile, true);
20769362b5b63875987b050354b6852db76cb799d8cGeorge Mount                        appender.write("<!-- From: " + layoutFile.toURI().toString() + " -->\n");
20869362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    } catch (IOException e) {
20969362b5b63875987b050354b6852db76cb799d8cGeorge Mount                        System.err.println("Could not update " + layoutFile + ": " +
21069362b5b63875987b050354b6852db76cb799d8cGeorge Mount                                e.getLocalizedMessage());
21169362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    } finally {
21269362b5b63875987b050354b6852db76cb799d8cGeorge Mount                        IOUtils.closeQuietly(appender);
21369362b5b63875987b050354b6852db76cb799d8cGeorge Mount                    }
21469362b5b63875987b050354b6852db76cb799d8cGeorge Mount                }
21569362b5b63875987b050354b6852db76cb799d8cGeorge Mount            }
21669362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
21769362b5b63875987b050354b6852db76cb799d8cGeorge Mount    }
21869362b5b63875987b050354b6852db76cb799d8cGeorge Mount
21969362b5b63875987b050354b6852db76cb799d8cGeorge Mount    private static boolean makeTargetDir(File dir) {
22069362b5b63875987b050354b6852db76cb799d8cGeorge Mount        if (dir.exists()) {
22169362b5b63875987b050354b6852db76cb799d8cGeorge Mount            return dir.isDirectory();
22269362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
22369362b5b63875987b050354b6852db76cb799d8cGeorge Mount
22469362b5b63875987b050354b6852db76cb799d8cGeorge Mount        return dir.mkdirs();
22569362b5b63875987b050354b6852db76cb799d8cGeorge Mount    }
22669362b5b63875987b050354b6852db76cb799d8cGeorge Mount
22769362b5b63875987b050354b6852db76cb799d8cGeorge Mount    private static class MakeFileWriter extends JavaFileWriter {
22869362b5b63875987b050354b6852db76cb799d8cGeorge Mount        private final File mSourceRoot;
22969362b5b63875987b050354b6852db76cb799d8cGeorge Mount        private int mErrorCount;
23069362b5b63875987b050354b6852db76cb799d8cGeorge Mount
23169362b5b63875987b050354b6852db76cb799d8cGeorge Mount        public MakeFileWriter(File sourceRoot) {
23269362b5b63875987b050354b6852db76cb799d8cGeorge Mount            mSourceRoot = sourceRoot;
23369362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
23469362b5b63875987b050354b6852db76cb799d8cGeorge Mount
23569362b5b63875987b050354b6852db76cb799d8cGeorge Mount        @Override
23669362b5b63875987b050354b6852db76cb799d8cGeorge Mount        public void writeToFile(String canonicalName, String contents) {
23769362b5b63875987b050354b6852db76cb799d8cGeorge Mount            String fileName = canonicalName.replace('.', File.separatorChar) + ".java";
23869362b5b63875987b050354b6852db76cb799d8cGeorge Mount            File sourceFile = new File(mSourceRoot, fileName);
23969362b5b63875987b050354b6852db76cb799d8cGeorge Mount            FileWriter writer = null;
24069362b5b63875987b050354b6852db76cb799d8cGeorge Mount            try {
24169362b5b63875987b050354b6852db76cb799d8cGeorge Mount                sourceFile.getParentFile().mkdirs();
24269362b5b63875987b050354b6852db76cb799d8cGeorge Mount                writer = new FileWriter(sourceFile);
24369362b5b63875987b050354b6852db76cb799d8cGeorge Mount                writer.write(contents);
24469362b5b63875987b050354b6852db76cb799d8cGeorge Mount            } catch (IOException e) {
24569362b5b63875987b050354b6852db76cb799d8cGeorge Mount                System.err.println("Could not write to " + sourceFile + ": " +
24669362b5b63875987b050354b6852db76cb799d8cGeorge Mount                        e.getLocalizedMessage());
24769362b5b63875987b050354b6852db76cb799d8cGeorge Mount                mErrorCount++;
24869362b5b63875987b050354b6852db76cb799d8cGeorge Mount            } finally {
24969362b5b63875987b050354b6852db76cb799d8cGeorge Mount                IOUtils.closeQuietly(writer);
25069362b5b63875987b050354b6852db76cb799d8cGeorge Mount            }
25169362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
25269362b5b63875987b050354b6852db76cb799d8cGeorge Mount
25369362b5b63875987b050354b6852db76cb799d8cGeorge Mount        public int getErrorCount() {
25469362b5b63875987b050354b6852db76cb799d8cGeorge Mount            return mErrorCount;
25569362b5b63875987b050354b6852db76cb799d8cGeorge Mount        }
25669362b5b63875987b050354b6852db76cb799d8cGeorge Mount    }
25769362b5b63875987b050354b6852db76cb799d8cGeorge Mount}
258