OSDN Git Service

am e41accf6: Merge change 6412 into donut
[android-x86/build.git] / tools / atree / atree.cpp
1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include "options.h"
5 #include "files.h"
6 #include "fs.h"
7 #include <set>
8 #include <iostream>
9 #include <sstream>
10
11 using namespace std;
12
13 bool g_debug = false;
14 vector<string> g_listFiles;
15 vector<string> g_inputBases;
16 map<string, string> g_variables;
17 string g_outputBase;
18 string g_dependency;
19 bool g_useHardLinks = false;
20
21 const char* USAGE =
22 "\n"
23 "Usage: atree OPTIONS\n"
24 "\n"
25 "Options:\n"
26 "  -f FILELIST    Specify one or more files containing the\n"
27 "                 list of files to copy.\n"
28 "  -I INPUTDIR    Specify one or more base directories in\n"
29 "                 which to look for the files\n"
30 "  -o OUTPUTDIR   Specify the directory to copy all of the\n"
31 "                 output files to.\n"
32 "  -l             Use hard links instead of copying the files.\n"
33 "  -m DEPENDENCY  Output a make-formatted file containing the list.\n"
34 "                 of files included.  It sets the variable ATREE_FILES.\n"
35 "  -v VAR=VAL     Replaces ${VAR} by VAL when reading input files.\n"
36 "\n"
37 "FILELIST file format:\n"
38 "  The FILELIST files contain the list of files that will end up\n"
39 "  in the final OUTPUTDIR.  Atree will look for files in the INPUTDIR\n"
40 "  directories in the order they are specified.\n"
41 "\n"
42 "  In a FILELIST file, comment lines start with a #.  Other lines\n"
43 "  are of the format:\n"
44 "\n"
45 "    DEST\n"
46 "    SRC DEST\n"
47 "    -SRCPATTERN\n"
48 "\n"
49 "  DEST should be path relative to the output directory.\n"
50 "  If SRC is supplied, the file names can be different.\n"
51 "  SRCPATTERN is a pattern for the filenames.\n"
52 "\n";
53
54 int usage()
55 {
56     fwrite(USAGE, strlen(USAGE), 1, stderr);
57     return 1;
58 }
59
60 static bool
61 add_variable(const char* arg) {
62     const char* p = arg;
63     while (*p && *p != '=') p++;
64
65     if (*p == 0 || p == arg || p[1] == 0) {
66         return false;
67     }
68
69     ostringstream var;
70     var << "${" << string(arg, p-arg) << "}";
71     g_variables[var.str()] = string(p+1);
72     return true;
73 }
74
75 int
76 main(int argc, char* const* argv)
77 {
78     int err;
79     bool done = false;
80     while (!done) {
81         int opt = getopt(argc, argv, "f:I:o:hlm:v:");
82         switch (opt)
83         {
84             case -1:
85                 done = true;
86                 break;
87             case 'f':
88                 g_listFiles.push_back(string(optarg));
89                 break;
90             case 'I':
91                 g_inputBases.push_back(string(optarg));
92                 break;
93             case 'o':
94                 if (g_outputBase.length() != 0) {
95                     fprintf(stderr, "%s: -o may only be supplied once -- "
96                                 "-o %s\n", argv[0], optarg);
97                     return usage();
98                 }
99                 g_outputBase = optarg;
100                 break;
101             case 'l':
102                 g_useHardLinks = true;
103                 break;
104             case 'm':
105                 if (g_dependency.length() != 0) {
106                     fprintf(stderr, "%s: -m may only be supplied once -- "
107                                 "-m %s\n", argv[0], optarg);
108                     return usage();
109                 }
110                 g_dependency = optarg;
111                 break;
112             case 'v':
113                 if (!add_variable(optarg)) {
114                     fprintf(stderr, "%s Invalid expression in '-v %s': "
115                             "expected format is '-v VAR=VALUE'.\n",
116                             argv[0], optarg);
117                     return usage();
118                 }
119                 break;
120             default:
121             case '?':
122             case 'h':
123                 return usage();
124         }
125     }
126     if (optind != argc) {
127         fprintf(stderr, "%s: invalid argument -- %s\n", argv[0], argv[optind]);
128         return usage();
129     }
130
131     if (g_listFiles.size() == 0) {
132         fprintf(stderr, "%s: At least one -f option must be supplied.\n",
133                  argv[0]);
134         return usage();
135     }
136
137     if (g_inputBases.size() == 0) {
138         fprintf(stderr, "%s: At least one -I option must be supplied.\n",
139                  argv[0]);
140         return usage();
141     }
142
143     if (g_outputBase.length() == 0) {
144         fprintf(stderr, "%s: -o option must be supplied.\n", argv[0]);
145         return usage();
146     }
147
148
149 #if 0
150     for (vector<string>::iterator it=g_listFiles.begin();
151                                 it!=g_listFiles.end(); it++) {
152         printf("-f \"%s\"\n", it->c_str());
153     }
154     for (vector<string>::iterator it=g_inputBases.begin();
155                                 it!=g_inputBases.end(); it++) {
156         printf("-I \"%s\"\n", it->c_str());
157     }
158     printf("-o \"%s\"\n", g_outputBase.c_str());
159     if (g_useHardLinks) {
160         printf("-l\n");
161     }
162 #endif
163
164     vector<FileRecord> files;
165     vector<FileRecord> more;
166     vector<string> excludes;
167     set<string> directories;
168     set<string> deleted;
169
170     // read file lists
171     for (vector<string>::iterator it=g_listFiles.begin();
172                                 it!=g_listFiles.end(); it++) {
173         err = read_list_file(*it, g_variables, &files, &excludes);
174         if (err != 0) {
175             return err;
176         }
177     }
178
179     // look for input files
180     err = 0;
181     for (vector<FileRecord>::iterator it=files.begin();
182                                 it!=files.end(); it++) {
183         err |= locate(&(*it), g_inputBases);
184
185     }
186     
187     // expand the directories that we should copy into a list of files
188     for (vector<FileRecord>::iterator it=files.begin();
189                                 it!=files.end(); it++) {
190         if (it->sourceIsDir) {
191             err |= list_dir(*it, excludes, &more);
192         }
193     }
194     for (vector<FileRecord>::iterator it=more.begin();
195                                 it!=more.end(); it++) {
196         files.push_back(*it);
197     }
198
199     // get the name and modtime of the output files
200     for (vector<FileRecord>::iterator it=files.begin();
201                                 it!=files.end(); it++) {
202         stat_out(g_outputBase, &(*it));
203     }
204
205     if (err != 0) {
206         return 1;
207     }
208
209     // gather directories
210     for (vector<FileRecord>::iterator it=files.begin();
211                                 it!=files.end(); it++) {
212         if (it->sourceIsDir) {
213             directories.insert(it->outPath);
214         } else {
215             string s = dir_part(it->outPath);
216             if (s != ".") {
217                 directories.insert(s);
218             }
219         }
220     }
221
222     // gather files that should become directores and directories that should
223     // become files
224     for (vector<FileRecord>::iterator it=files.begin();
225                                 it!=files.end(); it++) {
226         if (it->outMod != 0 && it->sourceIsDir != it->outIsDir) {
227             deleted.insert(it->outPath);
228         }
229     }
230
231     // delete files
232     for (set<string>::iterator it=deleted.begin();
233                                 it!=deleted.end(); it++) {
234         if (g_debug) {
235             printf("deleting %s\n", it->c_str());
236         }
237         err = remove_recursively(*it);
238         if (err != 0) {
239             return err;
240         }
241     }
242
243     // make directories
244     for (set<string>::iterator it=directories.begin();
245                                 it!=directories.end(); it++) {
246         if (g_debug) {
247             printf("mkdir %s\n", it->c_str());
248         }
249         err = mkdir_recursively(*it);
250         if (err != 0) {
251             return err;
252         }
253     }
254
255     // copy (or link) files
256     for (vector<FileRecord>::iterator it=files.begin();
257                                 it!=files.end(); it++) {
258         if (!it->sourceIsDir) {
259             if (g_debug) {
260                 printf("copy %s(%ld) ==> %s(%ld)", it->sourcePath.c_str(),
261                     it->sourceMod, it->outPath.c_str(), it->outMod);
262                 fflush(stdout);
263             }
264
265             if (it->outMod < it->sourceMod) {
266                 err = copy_file(it->sourcePath, it->outPath);
267                 if (g_debug) {
268                     printf(" done.\n");
269                 }
270                 if (err != 0) {
271                     return err;
272                 }
273             } else {
274                 if (g_debug) {
275                     printf(" skipping.\n");
276                 }
277             }
278         }
279     }
280
281     // output the dependency file
282     if (g_dependency.length() != 0) {
283         FILE *f = fopen(g_dependency.c_str(), "w");
284         if (f != NULL) {
285             fprintf(f, "ATREE_FILES := $(ATREE_FILES) \\\n");
286             for (vector<FileRecord>::iterator it=files.begin();
287                                 it!=files.end(); it++) {
288                 if (!it->sourceIsDir) {
289                     fprintf(f, "%s \\\n", it->sourcePath.c_str());
290                 }
291             }
292             fprintf(f, "\n");
293             fclose(f);
294         } else {
295             fprintf(stderr, "error opening manifest file for write: %s\n",
296                     g_dependency.c_str());
297         }
298     }
299
300     return 0;
301 }