001/*
002 * Forge Mod Loader
003 * Copyright (c) 2012-2013 cpw.
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser Public License v2.1
006 * which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
008 * 
009 * Contributors:
010 *     cpw - implementation
011 */
012
013package cpw.mods.fml.common.discovery;
014
015import java.io.File;
016import java.io.FileFilter;
017import java.io.FileInputStream;
018import java.util.Arrays;
019import java.util.List;
020import java.util.logging.Level;
021import java.util.regex.Matcher;
022
023import com.google.common.base.Throwables;
024import com.google.common.collect.Lists;
025
026import cpw.mods.fml.common.FMLLog;
027import cpw.mods.fml.common.LoaderException;
028import cpw.mods.fml.common.MetadataCollection;
029import cpw.mods.fml.common.ModContainer;
030import cpw.mods.fml.common.ModContainerFactory;
031import cpw.mods.fml.common.discovery.asm.ASMModParser;
032
033public class DirectoryDiscoverer implements ITypeDiscoverer
034{
035    private class ClassFilter implements FileFilter
036    {
037        @Override
038        public boolean accept(File file)
039        {
040            return (file.isFile() && classFile.matcher(file.getName()).find()) || file.isDirectory();
041        }
042    }
043
044    private ASMDataTable table;
045
046    @Override
047    public List<ModContainer> discover(ModCandidate candidate, ASMDataTable table)
048    {
049        this.table = table;
050        List<ModContainer> found = Lists.newArrayList();
051        FMLLog.fine("Examining directory %s for potential mods", candidate.getModContainer().getName());
052        exploreFileSystem("", candidate.getModContainer(), found, candidate, null);
053        for (ModContainer mc : found)
054        {
055            table.addContainer(mc);
056        }
057        return found;
058    }
059
060    public void exploreFileSystem(String path, File modDir, List<ModContainer> harvestedMods, ModCandidate candidate, MetadataCollection mc)
061    {
062        if (path.length() == 0)
063        {
064            File metadata = new File(modDir, "mcmod.info");
065            try
066            {
067                FileInputStream fis = new FileInputStream(metadata);
068                mc = MetadataCollection.from(fis,modDir.getName());
069                fis.close();
070                FMLLog.fine("Found an mcmod.info file in directory %s", modDir.getName());
071            }
072            catch (Exception e)
073            {
074                mc = MetadataCollection.from(null,"");
075                FMLLog.fine("No mcmod.info file found in directory %s", modDir.getName());
076            }
077        }
078
079        File[] content = modDir.listFiles(new ClassFilter());
080
081        // Always sort our content
082        Arrays.sort(content);
083        for (File file : content)
084        {
085            if (file.isDirectory())
086            {
087                FMLLog.finest("Recursing into package %s", path + file.getName());
088                exploreFileSystem(path + file.getName() + ".", file, harvestedMods, candidate, mc);
089                continue;
090            }
091            Matcher match = classFile.matcher(file.getName());
092
093            if (match.matches())
094            {
095                ASMModParser modParser = null;
096                try
097                {
098                    FileInputStream fis = new FileInputStream(file);
099                    modParser = new ASMModParser(fis);
100                    fis.close();
101                }
102                catch (LoaderException e)
103                {
104                    FMLLog.log(Level.SEVERE, e, "There was a problem reading the file %s - probably this is a corrupt file", file.getPath());
105                    throw e;
106                }
107                catch (Exception e)
108                {
109                    Throwables.propagate(e);
110                }
111
112                modParser.validate();
113                modParser.sendToTable(table, candidate);
114                ModContainer container = ModContainerFactory.instance().build(modParser, candidate.getModContainer(), candidate);
115                if (container!=null)
116                {
117                    harvestedMods.add(container);
118                    container.bindMetadata(mc);
119                }
120            }
121
122
123        }
124    }
125
126}