15 bool g_debug = getenv("ATREE_DEBUG") != NULL;
16 vector<string> g_listFiles;
17 vector<string> g_inputBases;
18 map<string, string> g_variables;
21 bool g_useHardLinks = false;
25 "Usage: atree OPTIONS\n"
28 " -f FILELIST Specify one or more files containing the\n"
29 " list of files to copy.\n"
30 " -I INPUTDIR Specify one or more base directories in\n"
31 " which to look for the files\n"
32 " -o OUTPUTDIR Specify the directory to copy all of the\n"
34 " -l Use hard links instead of copying the files.\n"
35 " -m DEPENDENCY Output a make-formatted file containing the list.\n"
36 " of files included. It sets the variable ATREE_FILES.\n"
37 " -v VAR=VAL Replaces ${VAR} by VAL when reading input files.\n"
38 " -d Verbose debug mode.\n"
40 "FILELIST file format:\n"
41 " The FILELIST files contain the list of files that will end up\n"
42 " in the final OUTPUTDIR. Atree will look for files in the INPUTDIR\n"
43 " directories in the order they are specified.\n"
45 " In a FILELIST file, comment lines start with a #. Other lines\n"
46 " are of the format:\n"
52 " DEST should be path relative to the output directory.\n"
53 " 'rm DEST' removes the destination file and fails if it's missing.\n"
54 " 'strip DEST' strips the binary destination file.\n"
55 " If SRC is supplied, the file names can be different.\n"
56 " SRCPATTERN is a pattern for the filenames.\n"
61 fwrite(USAGE, strlen(USAGE), 1, stderr);
66 add_variable(const char* arg) {
68 while (*p && *p != '=') p++;
70 if (*p == 0 || p == arg || p[1] == 0) {
75 var << "${" << string(arg, p-arg) << "}";
76 g_variables[var.str()] = string(p+1);
81 debug_printf(const char* format, ...)
94 main(int argc, char* const* argv)
99 int opt = getopt(argc, argv, "f:I:o:hlm:v:d");
106 g_listFiles.push_back(string(optarg));
109 g_inputBases.push_back(string(optarg));
112 if (g_outputBase.length() != 0) {
113 fprintf(stderr, "%s: -o may only be supplied once -- "
114 "-o %s\n", argv[0], optarg);
117 g_outputBase = optarg;
120 g_useHardLinks = true;
123 if (g_dependency.length() != 0) {
124 fprintf(stderr, "%s: -m may only be supplied once -- "
125 "-m %s\n", argv[0], optarg);
128 g_dependency = optarg;
131 if (!add_variable(optarg)) {
132 fprintf(stderr, "%s Invalid expression in '-v %s': "
133 "expected format is '-v VAR=VALUE'.\n",
147 if (optind != argc) {
148 fprintf(stderr, "%s: invalid argument -- %s\n", argv[0], argv[optind]);
152 if (g_listFiles.size() == 0) {
153 fprintf(stderr, "%s: At least one -f option must be supplied.\n",
158 if (g_inputBases.size() == 0) {
159 fprintf(stderr, "%s: At least one -I option must be supplied.\n",
164 if (g_outputBase.length() == 0) {
165 fprintf(stderr, "%s: -o option must be supplied.\n", argv[0]);
171 for (vector<string>::iterator it=g_listFiles.begin();
172 it!=g_listFiles.end(); it++) {
173 printf("-f \"%s\"\n", it->c_str());
175 for (vector<string>::iterator it=g_inputBases.begin();
176 it!=g_inputBases.end(); it++) {
177 printf("-I \"%s\"\n", it->c_str());
179 printf("-o \"%s\"\n", g_outputBase.c_str());
180 if (g_useHardLinks) {
185 vector<FileRecord> files;
186 vector<FileRecord> more;
187 vector<string> excludes;
188 set<string> directories;
192 for (vector<string>::iterator it=g_listFiles.begin();
193 it!=g_listFiles.end(); it++) {
194 err = read_list_file(*it, g_variables, &files, &excludes);
200 // look for input files
202 for (vector<FileRecord>::iterator it=files.begin();
203 it!=files.end(); it++) {
204 err |= locate(&(*it), g_inputBases);
207 // expand the directories that we should copy into a list of files
208 for (vector<FileRecord>::iterator it=files.begin();
209 it!=files.end(); it++) {
210 if (it->sourceIsDir) {
211 err |= list_dir(*it, excludes, &more);
214 for (vector<FileRecord>::iterator it=more.begin();
215 it!=more.end(); it++) {
216 files.push_back(*it);
219 // get the name and modtime of the output files
220 for (vector<FileRecord>::iterator it=files.begin();
221 it!=files.end(); it++) {
222 stat_out(g_outputBase, &(*it));
229 // gather directories
230 for (vector<FileRecord>::iterator it=files.begin();
231 it!=files.end(); it++) {
232 if (it->sourceIsDir) {
233 directories.insert(it->outPath);
235 string s = dir_part(it->outPath);
237 directories.insert(s);
242 // gather files that should become directores
243 // and directories that should become files
244 for (vector<FileRecord>::iterator it=files.begin();
245 it!=files.end(); it++) {
246 if (it->outMod != 0 && it->sourceIsDir != it->outIsDir) {
247 deleted.insert(it->outPath);
252 for (set<string>::iterator it=deleted.begin();
253 it!=deleted.end(); it++) {
254 debug_printf("deleting %s\n", it->c_str());
255 err = remove_recursively(*it);
261 // remove all files or directories as requested from the input atree file.
262 // must be done before create new directories.
263 for (vector<FileRecord>::iterator it=files.begin();
264 it!=files.end(); it++) {
265 if (!it->sourceIsDir) {
266 if (it->fileOp == FILE_OP_REMOVE &&
267 deleted.count(it->outPath) == 0) {
268 debug_printf("remove %s\n", it->outPath.c_str());
269 err = remove_recursively(it->outPath);
278 for (set<string>::iterator it=directories.begin();
279 it!=directories.end(); it++) {
280 debug_printf("mkdir %s\n", it->c_str());
281 err = mkdir_recursively(*it);
287 // copy (or link) files that are newer or of different size
288 for (vector<FileRecord>::iterator it=files.begin();
289 it!=files.end(); it++) {
290 if (!it->sourceIsDir) {
291 if (it->fileOp == FILE_OP_REMOVE) {
295 debug_printf("copy %s(%ld) ==> %s(%ld)",
296 it->sourcePath.c_str(), it->sourceMod,
297 it->outPath.c_str(), it->outMod);
299 if (it->outSize != it->sourceSize || it->outMod < it->sourceMod) {
300 err = copy_file(it->sourcePath, it->outPath);
301 debug_printf(" done.\n");
306 debug_printf(" skipping.\n");
309 if (it->fileOp == FILE_OP_STRIP) {
310 debug_printf("strip %s\n", it->outPath.c_str());
311 err = strip_file(it->outPath);
319 // output the dependency file
320 if (g_dependency.length() != 0) {
321 FILE *f = fopen(g_dependency.c_str(), "w");
323 fprintf(f, "ATREE_FILES := $(ATREE_FILES) \\\n");
324 for (vector<FileRecord>::iterator it=files.begin();
325 it!=files.end(); it++) {
326 if (!it->sourceIsDir) {
327 fprintf(f, "%s \\\n", it->sourcePath.c_str());
333 fprintf(stderr, "error opening manifest file for write: %s\n",
334 g_dependency.c_str());