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());