summaryrefslogtreecommitdiffstats
path: root/tools/atree/atree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/atree/atree.cpp')
-rw-r--r--tools/atree/atree.cpp274
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;
+}