diff options
Diffstat (limited to 'tools/atree/atree.cpp')
-rw-r--r-- | tools/atree/atree.cpp | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/tools/atree/atree.cpp b/tools/atree/atree.cpp new file mode 100644 index 0000000..4d97d24 --- /dev/null +++ b/tools/atree/atree.cpp @@ -0,0 +1,274 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include "options.h" +#include "files.h" +#include "fs.h" +#include <set> + +using namespace std; + +bool g_debug = false; +vector<string> g_listFiles; +vector<string> g_inputBases; +string g_outputBase; +string g_dependency; +bool g_useHardLinks = false; + +const char* USAGE = +"\n" +"Usage: atree OPTIONS\n" +"\n" +"Options:\n" +" -f FILELIST Specify one or more files containing the\n" +" list of files to copy.\n" +" -I INPUTDIR Specify one or more base directories in\n" +" which to look for the files\n" +" -o OUTPUTDIR Specify the directory to copy all of the\n" +" output files to.\n" +" -l Use hard links instead of copying the files.\n" +" -m DEPENDENCY Output a make-formatted file containing the list.\n" +" of files included. It sets the variable ATREE_FILES.\n" +"\n" +"FILELIST file format:\n" +" The FILELIST files contain the list of files that will end up\n" +" in the final OUTPUTDIR. Atree will look for files in the INPUTDIR\n" +" directories in the order they are specified.\n" +"\n" +" In a FILELIST file, comment lines start with a #. Other lines\n" +" are of the format:\n" +"\n" +" DEST\n" +" SRC DEST\n" +" -SRCPATTERN\n" +"\n" +" DEST should be path relative to the output directory.\n" +" If SRC is supplied, the file names can be different.\n" +" SRCPATTERN is a pattern for the filenames.\n" +"\n"; + +int usage() +{ + fwrite(USAGE, strlen(USAGE), 1, stderr); + return 1; +} + +int +main(int argc, char* const* argv) +{ + int err; + bool done = false; + while (!done) { + int opt = getopt(argc, argv, "f:I:o:hlm:"); + switch (opt) + { + case -1: + done = true; + break; + case 'f': + g_listFiles.push_back(string(optarg)); + break; + case 'I': + g_inputBases.push_back(string(optarg)); + break; + case 'o': + if (g_outputBase.length() != 0) { + fprintf(stderr, "%s: -o may only be supplied once -- " + "-o %s\n", argv[0], optarg); + return usage(); + } + g_outputBase = optarg; + break; + case 'l': + g_useHardLinks = true; + break; + case 'm': + if (g_dependency.length() != 0) { + fprintf(stderr, "%s: -m may only be supplied once -- " + "-m %s\n", argv[0], optarg); + return usage(); + } + g_dependency = optarg; + break; + default: + case '?': + case 'h': + return usage(); + } + } + if (optind != argc) { + fprintf(stderr, "%s: invalid argument -- %s\n", argv[0], argv[optind]); + return usage(); + } + + if (g_listFiles.size() == 0) { + fprintf(stderr, "%s: At least one -f option must be supplied.\n", + argv[0]); + return usage(); + } + + if (g_inputBases.size() == 0) { + fprintf(stderr, "%s: At least one -I option must be supplied.\n", + argv[0]); + return usage(); + } + + if (g_outputBase.length() == 0) { + fprintf(stderr, "%s: -o option must be supplied.\n", argv[0]); + return usage(); + } + + +#if 0 + for (vector<string>::iterator it=g_listFiles.begin(); + it!=g_listFiles.end(); it++) { + printf("-f \"%s\"\n", it->c_str()); + } + for (vector<string>::iterator it=g_inputBases.begin(); + it!=g_inputBases.end(); it++) { + printf("-I \"%s\"\n", it->c_str()); + } + printf("-o \"%s\"\n", g_outputBase.c_str()); + if (g_useHardLinks) { + printf("-l\n"); + } +#endif + + vector<FileRecord> files; + vector<FileRecord> more; + vector<string> excludes; + set<string> directories; + set<string> deleted; + + // read file lists + for (vector<string>::iterator it=g_listFiles.begin(); + it!=g_listFiles.end(); it++) { + err = read_list_file(*it, &files, &excludes); + if (err != 0) { + return err; + } + } + + // look for input files + err = 0; + for (vector<FileRecord>::iterator it=files.begin(); + it!=files.end(); it++) { + err |= locate(&(*it), g_inputBases); + + } + + // expand the directories that we should copy into a list of files + for (vector<FileRecord>::iterator it=files.begin(); + it!=files.end(); it++) { + if (it->sourceIsDir) { + err |= list_dir(*it, excludes, &more); + } + } + for (vector<FileRecord>::iterator it=more.begin(); + it!=more.end(); it++) { + files.push_back(*it); + } + + // get the name and modtime of the output files + for (vector<FileRecord>::iterator it=files.begin(); + it!=files.end(); it++) { + stat_out(g_outputBase, &(*it)); + } + + if (err != 0) { + return 1; + } + + // gather directories + for (vector<FileRecord>::iterator it=files.begin(); + it!=files.end(); it++) { + if (it->sourceIsDir) { + directories.insert(it->outPath); + } else { + string s = dir_part(it->outPath); + if (s != ".") { + directories.insert(s); + } + } + } + + // gather files that should become directores and directories that should + // become files + for (vector<FileRecord>::iterator it=files.begin(); + it!=files.end(); it++) { + if (it->outMod != 0 && it->sourceIsDir != it->outIsDir) { + deleted.insert(it->outPath); + } + } + + // delete files + for (set<string>::iterator it=deleted.begin(); + it!=deleted.end(); it++) { + if (g_debug) { + printf("deleting %s\n", it->c_str()); + } + err = remove_recursively(*it); + if (err != 0) { + return err; + } + } + + // make directories + for (set<string>::iterator it=directories.begin(); + it!=directories.end(); it++) { + if (g_debug) { + printf("mkdir %s\n", it->c_str()); + } + err = mkdir_recursively(*it); + if (err != 0) { + return err; + } + } + + // copy (or link) files + for (vector<FileRecord>::iterator it=files.begin(); + it!=files.end(); it++) { + if (!it->sourceIsDir) { + if (g_debug) { + printf("copy %s(%ld) ==> %s(%ld)", it->sourcePath.c_str(), + it->sourceMod, it->outPath.c_str(), it->outMod); + fflush(stdout); + } + + if (it->outMod < it->sourceMod) { + err = copy_file(it->sourcePath, it->outPath); + if (g_debug) { + printf(" done.\n"); + } + if (err != 0) { + return err; + } + } else { + if (g_debug) { + printf(" skipping.\n"); + } + } + } + } + + // output the dependency file + if (g_dependency.length() != 0) { + FILE *f = fopen(g_dependency.c_str(), "w"); + if (f != NULL) { + fprintf(f, "ATREE_FILES := $(ATREE_FILES) \\\n"); + for (vector<FileRecord>::iterator it=files.begin(); + it!=files.end(); it++) { + if (!it->sourceIsDir) { + fprintf(f, "%s \\\n", it->sourcePath.c_str()); + } + } + fprintf(f, "\n"); + fclose(f); + } else { + fprintf(stderr, "error opening manifest file for write: %s\n", + g_dependency.c_str()); + } + } + + return 0; +} |