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

Commit 131292c0 authored by Raphael's avatar Raphael Committed by Raphael Moll
Browse files

Add rm and strip abilities to atree. DO NOT MERGE.

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.

Cherry-pick from master 0b3ec5d3
parent 704c0c9f
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