Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b3ec5d3 authored by Raphael's avatar Raphael
Browse files

Add rm and strip abilities to atree.

The new line syntax is:
  [SRC] [rm|strip] DEST

This allows one to write things like this in atree:

  bin/src
  bin/src bin/dest
  bin/src "bin/another file name"

  rm dest/file
  rm dest/dir  # recursive

  strip bin/src
  bin/src strip bin/dest

Src and dest can contain spaces if full enclosed in double-quotes.
The strip command can be overridden using the STRIP env var.

Change-Id: I22aae7a87c36c082e1aab87132099a3c644914da
parent 4d7ddab1
Loading
Loading
Loading
Loading
+64 −26
Original line number Diff line number Diff line
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include "options.h"
#include "files.h"
#include "fs.h"
@@ -10,7 +12,7 @@

using namespace std;

bool g_debug = false;
bool g_debug = getenv("ATREE_DEBUG") != NULL;
vector<string> g_listFiles;
vector<string> g_inputBases;
map<string, string> g_variables;
@@ -33,6 +35,7 @@ const char* USAGE =
"  -m DEPENDENCY  Output a make-formatted file containing the list.\n"
"                 of files included.  It sets the variable ATREE_FILES.\n"
"  -v VAR=VAL     Replaces ${VAR} by VAL when reading input files.\n"
"  -d             Verbose debug mode.\n"
"\n"
"FILELIST file format:\n"
"  The FILELIST files contain the list of files that will end up\n"
@@ -42,11 +45,13 @@ const char* USAGE =
"  In a FILELIST file, comment lines start with a #.  Other lines\n"
"  are of the format:\n"
"\n"
"    DEST\n"
"    SRC DEST\n"
"    [rm|strip] DEST\n"
"    SRC [strip] DEST\n"
"    -SRCPATTERN\n"
"\n"
"  DEST should be path relative to the output directory.\n"
"  'rm DEST' removes the destination file and fails if it's missing.\n"
"  'strip DEST' strips the binary destination file.\n"
"  If SRC is supplied, the file names can be different.\n"
"  SRCPATTERN is a pattern for the filenames.\n"
"\n";
@@ -72,13 +77,26 @@ add_variable(const char* arg) {
    return true;
}

static void
debug_printf(const char* format, ...)
{
    if (g_debug) {
        fflush(stderr);
        va_list ap;
        va_start(ap, format);
        vprintf(format, ap);
        va_end(ap);
        fflush(stdout);
    }
}

int
main(int argc, char* const* argv)
{
    int err;
    bool done = false;
    while (!done) {
        int opt = getopt(argc, argv, "f:I:o:hlm:v:");
        int opt = getopt(argc, argv, "f:I:o:hlm:v:d");
        switch (opt)
        {
            case -1:
@@ -117,6 +135,9 @@ main(int argc, char* const* argv)
                    return usage();
                }
                break;
            case 'd':
                g_debug = true;
                break;
            default:
            case '?':
            case 'h':
@@ -181,7 +202,6 @@ main(int argc, char* const* argv)
    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
@@ -219,8 +239,8 @@ main(int argc, char* const* argv)
        }
    }

    // gather files that should become directores and directories that should
    // become files
    // 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) {
@@ -231,48 +251,66 @@ main(int argc, char* const* argv)
    // delete files
    for (set<string>::iterator it=deleted.begin();
                                it!=deleted.end(); it++) {
        if (g_debug) {
            printf("deleting %s\n", it->c_str());
        }
        debug_printf("deleting %s\n", it->c_str());
        err = remove_recursively(*it);
        if (err != 0) {
            return err;
        }
    }

    // remove all files or directories as requested from the input atree file.
    // must be done before create new directories.
    for (vector<FileRecord>::iterator it=files.begin();
                                it!=files.end(); it++) {
        if (!it->sourceIsDir) {
            if (it->fileOp == FILE_OP_REMOVE &&
                    deleted.count(it->outPath) == 0) {
                debug_printf("remove %s\n", it->outPath.c_str());
                err = remove_recursively(it->outPath);
                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());
        }
        debug_printf("mkdir %s\n", it->c_str());
        err = mkdir_recursively(*it);
        if (err != 0) {
            return err;
        }
    }

    // copy (or link) files
    // copy (or link) files that are newer or of different size
    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->fileOp == FILE_OP_REMOVE) {
                continue;
            }

            if (it->outMod < it->sourceMod) {
            debug_printf("copy %s(%ld) ==> %s(%ld)",
                it->sourcePath.c_str(), it->sourceMod,
                it->outPath.c_str(), it->outMod);

            if (it->outSize != it->sourceSize || it->outMod < it->sourceMod) {
                err = copy_file(it->sourcePath, it->outPath);
                if (g_debug) {
                    printf(" done.\n");
                }
                debug_printf(" done.\n");
                if (err != 0) {
                    return err;
                }
            } else {
                if (g_debug) {
                    printf(" skipping.\n");
                debug_printf(" skipping.\n");
            }

            if (it->fileOp == FILE_OP_STRIP) {
                debug_printf("strip %s\n", it->outPath.c_str());
                err = strip_file(it->outPath);
                if (err != 0) {
                    return err;
                }
            }
        }
+85 −32
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ void
split_line(const char* p, vector<string>* out)
{
    const char* q = p;
    enum { WHITE, TEXT } state = WHITE;
    enum { WHITE, TEXT, IN_QUOTE } state = WHITE;
    while (*p) {
        if (*p == '#') {
            break;
@@ -73,13 +73,25 @@ split_line(const char* p, vector<string>* out)
            case WHITE:
                if (!isspace(*p)) {
                    q = p;
                    state = TEXT;
                    state = (*p == '"') ? IN_QUOTE : TEXT;
                }
                break;
            case IN_QUOTE:
                if (*p == '"') {
                    state = TEXT;
                    break;
                }
                // otherwise fall-through to TEXT case
            case TEXT:
                if (isspace(*p)) {
                if (state != IN_QUOTE && isspace(*p)) {
                    if (q != p) {
                        out->push_back(string(q, p-q));
                        const char* start = q;
                        size_t len = p-q;
                        if (len > 2 && *start == '"' && start[len - 1] == '"') {
                            start++;
                            len -= 2;
                        }
                        out->push_back(string(start, len));
                    }
                    state = WHITE;
                }
@@ -88,17 +100,25 @@ split_line(const char* p, vector<string>* out)
        p++;
    }
    if (state == TEXT) {
        out->push_back(string(q, p-q));
        const char* start = q;
        size_t len = p-q;
        if (len > 2 && *start == '"' && start[len - 1] == '"') {
            start++;
            len -= 2;
        }
        out->push_back(string(start, len));
    }
}

static void
add_file(vector<FileRecord>* files, const string& listFile, int listLine,
add_file(vector<FileRecord>* files, const FileOpType fileOp,
            const string& listFile, int listLine,
            const string& sourceName, const string& outName)
{
    FileRecord rec;
    rec.listFile = listFile;
    rec.listLine = listLine;
    rec.fileOp = fileOp;
    rec.sourceName = sourceName;
    rec.outName = outName;
    files->push_back(rec);
@@ -245,35 +265,52 @@ read_list_file(const string& filename,
            }
            printf("]\n");
#endif
            
            if (words.size() == 1) {
                // pattern: DEST
                bool error = false;
                string w0 = replace_variables(words[0], variables, &error);
                if (error) {
                    err = 1;
                    goto cleanup;
            FileOpType op = FILE_OP_COPY;
            string paths[2];
            int pcount = 0;
            string errstr;
            for (vector<string>::iterator it = words.begin(); it != words.end(); ++it) {
                const string& word = *it;
                if (word == "rm") {
                    if (op != FILE_OP_COPY) {
                        errstr = "Error: you can only specifiy 'rm' or 'strip' once per line.";
                        break;
                    }
                add_file(files, filename, i+1, w0, w0);
                    op = FILE_OP_REMOVE;
                } else if (word == "strip") {
                    if (op != FILE_OP_COPY) {
                        errstr = "Error: you can only specifiy 'rm' or 'strip' once per line.";
                        break;
                    }
            else if (words.size() == 2) {
                // pattern: SRC DEST
                    op = FILE_OP_STRIP;
                } else if (pcount < 2) {
                    bool error = false;
                string w0, w1;
                w0 = replace_variables(words[0], variables, &error);
                if (!error) {
                    w1 = replace_variables(words[1], variables, &error);
                }
                    paths[pcount++] = replace_variables(word, variables, &error);
                    if (error) {
                        err = 1;
                        goto cleanup;
                    }
                add_file(files, filename, i+1, w0, w1);
                } else {
                    errstr = "Error: More than 2 paths per line.";
                    break;
                }
            }
            else {
                fprintf(stderr, "%s:%d: bad format: %s\n", filename.c_str(),
                        i+1, p);

            if (pcount == 0 && !errstr.empty()) {
                errstr = "Error: No path found on line.";
            }

            if (!errstr.empty()) {
                fprintf(stderr, "%s:%d: bad format: %s\n%s\nExpected: [SRC] [rm|strip] DEST\n",
                        filename.c_str(), i+1, p, errstr.c_str());
                err = 1;
            } else {
                if (pcount == 1) {
                    // pattern: [rm|strip] DEST
                    paths[1] = paths[0];
                }

                add_file(files, op, filename, i+1, paths[0], paths[1]);
            }
        }
        p = q;
@@ -293,6 +330,14 @@ cleanup:
int
locate(FileRecord* rec, const vector<string>& search)
{
    if (rec->fileOp == FILE_OP_REMOVE) {
        // Don't touch source files when removing a destination.
        rec->sourceMod = 0;
        rec->sourceSize = 0;
        rec->sourceIsDir = false;
        return 0;
    }

    int err;

    for (vector<string>::const_iterator it=search.begin();
@@ -304,6 +349,7 @@ locate(FileRecord* rec, const vector<string>& search)
            rec->sourceBase = *it;
            rec->sourcePath = full;
            rec->sourceMod = st.st_mtime;
            rec->sourceSize = st.st_size;
            rec->sourceIsDir = S_ISDIR(st.st_mode);
            return 0;
        }
@@ -324,9 +370,11 @@ stat_out(const string& base, FileRecord* rec)
    err = stat(rec->outPath.c_str(), &st);
    if (err == 0) {
        rec->outMod = st.st_mtime;
        rec->outSize = st.st_size;
        rec->outIsDir = S_ISDIR(st.st_mode);
    } else {
        rec->outMod = 0;
        rec->outSize = 0;
        rec->outIsDir = false;
    }
}
@@ -427,3 +475,8 @@ list_dir(const FileRecord& rec, const vector<string>& excludes,
{
    return list_dir("", rec, excludes, files);
}

FileRecord::FileRecord() {
    fileOp = FILE_OP_COPY;
}
+11 −0
Original line number Diff line number Diff line
@@ -8,8 +8,16 @@

using namespace std;

enum FileOpType {
    FILE_OP_COPY = 0,
    FILE_OP_REMOVE,
    FILE_OP_STRIP
};

struct FileRecord
{
    FileRecord();

    string listFile;
    int listLine;

@@ -18,9 +26,12 @@ struct FileRecord
    string sourcePath;
    bool sourceIsDir;
    time_t sourceMod;
    off_t  sourceSize;
    FileOpType fileOp;

    string outName;
    string outPath;
    off_t  outSize;
    time_t outMod;
    bool outIsDir;
    unsigned int mode;
+30 −4
Original line number Diff line number Diff line
#include "fs.h"
#include "files.h"
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <string>
#include <vector>
@@ -146,3 +148,27 @@ copy_file(const string& src, const string& dst)
                    COPY_NO_DEREFERENCE | COPY_FORCE | COPY_PERMISSIONS);
    return err;
}

int
strip_file(const string& path)
{
    // Default strip command to run is "strip" unless overridden by the STRIP env var.
    const char* strip_cmd = getenv("STRIP");
    if (!strip_cmd || !strip_cmd[0]) {
        strip_cmd = "strip";
    }
    pid_t pid = fork();
    if (pid == -1) {
        // Fork failed. errno should be set.
        return -1;
    } else if (pid == 0) {
        // Exec in the child. Only returns if execve failed.
        return execlp(strip_cmd, strip_cmd, path.c_str(), (char *)NULL);
    } else {
        // Wait for child pid and return its exit code.
        int status;
        waitpid(pid, &status, 0);
        return status;
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -8,5 +8,6 @@ using namespace std;
int remove_recursively(const string& path);
int mkdir_recursively(const string& path);
int copy_file(const string& src, const string& dst);
int strip_file(const string& path);

#endif // FS_H