1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.eclipse.org/org/documents/epl-v10.php
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.ide.eclipse.adt.internal.build.builders;
18
19import com.android.ide.eclipse.adt.AdtPlugin;
20import com.android.ide.eclipse.adt.internal.build.BuildHelper;
21
22import org.eclipse.core.resources.IFolder;
23import org.eclipse.core.resources.IProject;
24import org.eclipse.core.resources.IResource;
25import org.eclipse.core.resources.IResourceDelta;
26import org.eclipse.core.resources.IResourceDeltaVisitor;
27import org.eclipse.core.runtime.CoreException;
28import org.eclipse.core.runtime.IPath;
29import org.eclipse.core.runtime.IStatus;
30
31import java.util.ArrayList;
32import java.util.IdentityHashMap;
33import java.util.List;
34import java.util.Map;
35
36/**
37 * Delta visitor checking changed files against given glob-patterns.
38 *
39 * The visitor is given {@link ChangedFileSet} objects which contains patterns to detect change
40 * in input and output files. (Output files are only tested if the delta indicate the file
41 * was removed).
42 *
43 * After the visitor has visited the whole delta, it can be queried to see which ChangedFileSet
44 * recognized a file change. (ChangedFileSet are immutable and do not record this info).
45 */
46class PatternBasedDeltaVisitor implements IResourceDeltaVisitor {
47
48    private final static boolean DEBUG_LOG = "1".equals(              //$NON-NLS-1$
49            System.getenv("ANDROID_VISITOR_DEBUG"));                  //$NON-NLS-1$
50
51    private final IProject mMainProject;
52    private final IProject mDeltaProject;
53
54    private final List<ChangedFileSet> mSets = new ArrayList<ChangedFileSet>();
55    private final Map<ChangedFileSet, Boolean> mResults =
56            new IdentityHashMap<ChangedFileSet, Boolean>();
57
58    private final String mLogName;
59
60    PatternBasedDeltaVisitor(IProject mainProject, IProject deltaProject, String logName) {
61        mMainProject = mainProject;
62        mDeltaProject = deltaProject;
63        mLogName = logName;
64        if (DEBUG_LOG) {
65            AdtPlugin.log(IStatus.INFO, "%s (%s): Delta for %s",               //$NON-NLS-1$
66                    mMainProject.getName(), mLogName, mDeltaProject.getName());
67        }
68    }
69
70    void addSet(ChangedFileSet bundle) {
71        mSets.add(bundle);
72    }
73
74    boolean checkSet(ChangedFileSet bundle) {
75        Boolean r = mResults.get(bundle);
76        if (r != null) {
77            return r.booleanValue();
78        }
79
80        return false;
81    }
82
83    @Override
84    public boolean visit(IResourceDelta delta) throws CoreException {
85        IResource resource = delta.getResource();
86
87        if (resource.getType() == IResource.FOLDER) {
88            // always visit the subfolders, unless the folder is not to be included
89            return BuildHelper.checkFolderForPackaging((IFolder)resource);
90
91        } else if (resource.getType() == IResource.FILE) {
92            IPath path = resource.getFullPath().makeRelativeTo(mDeltaProject.getFullPath());
93
94            // FIXME: no need to loop through all the sets once they have all said they need something (return false below and above)
95            for (ChangedFileSet set : mSets) {
96                // FIXME: should ignore sets that have already returned true.
97                String pathStr = path.toString();
98
99                if (set.isInput(pathStr, path)) {
100                    mResults.put(set, Boolean.TRUE);
101
102                    if (DEBUG_LOG) {
103                        String cfs_logName = set.getLogName();
104
105                        if (cfs_logName != null) {
106                            AdtPlugin.log(IStatus.INFO, "%s (%s:%s): %s",              //$NON-NLS-1$
107                                    mMainProject.getName(), mLogName, cfs_logName,
108                                    resource.getFullPath().toString());
109                        } else {
110                            AdtPlugin.log(IStatus.INFO, "%s (%s): %s",                 //$NON-NLS-1$
111                                    mMainProject.getName(), mLogName,
112                                    resource.getFullPath().toString());
113                        }
114                    }
115
116                } else if (delta.getKind() == IResourceDelta.REMOVED &&
117                        set.isOutput(pathStr, path)) {
118                    mResults.put(set, Boolean.TRUE);
119
120                    if (DEBUG_LOG) {
121                        String cfs_logName = set.getLogName();
122
123                        if (cfs_logName != null) {
124                            AdtPlugin.log(IStatus.INFO, "%s (%s:%s): %s",              //$NON-NLS-1$
125                                    mMainProject.getName(), mLogName, cfs_logName,
126                                    resource.getFullPath().toString());
127                        } else {
128                            AdtPlugin.log(IStatus.INFO, "%s (%s): %s",                 //$NON-NLS-1$
129                                    mMainProject.getName(), mLogName,
130                                    resource.getFullPath().toString());
131                        }
132                    }
133                }
134            }
135        }
136
137        return true;
138    }
139}
140