tools: don't assume modules are immediately below ccan/ dir.
authorRusty Russell <rusty@rustcorp.com.au>
Thu, 22 Nov 2012 00:32:19 +0000 (11:02 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Thu, 22 Nov 2012 00:32:19 +0000 (11:02 +1030)
Removing this assumption should allow nested modules.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
23 files changed:
tools/Makefile
tools/ccan_dir.c
tools/ccanlint/licenses.c
tools/ccanlint/tests/avoids_cpp_reserved.c
tools/ccanlint/tests/depends_accurate.c
tools/ccanlint/tests/depends_build.c
tools/ccanlint/tests/depends_build_without_features.c
tools/ccanlint/tests/depends_exist.c
tools/ccanlint/tests/examples_compile.c
tools/ccanlint/tests/headers_idempotent.c
tools/ccanlint/tests/info_documentation_exists.c
tools/ccanlint/tests/info_exists.c
tools/ccanlint/tests/license_depends_compat.c
tools/ccanlint/tests/license_exists.c
tools/ccanlint/tests/main_header_compiles.c
tools/ccanlint/tests/main_header_exists.c
tools/ccanlint/tests/module_links.c
tools/ccanlint/tests/objects_build_with_stringchecks.c
tools/ccanlint/tests/tests_exist.c
tools/depends.c
tools/doc_extract-core.c
tools/manifest.c
tools/manifest.h

index c60f06968b045ad271cc5d6689b88eef2454b265..d3d1904e395caf281fd87ca1b135d69e2945733a 100644 (file)
@@ -11,6 +11,7 @@ DEP_OBJS = ccan/err/err.o \
        ccan/talloc/talloc.o \
        ccan/time/time.o \
        tools/read_config_header.o \
+       tools/ccan_dir.o \
        tools/compile.o \
        tools/depends.o \
        tools/tools.o
index 0bb9b14457c73aad61a7473085a07232b3af2d4e..561488686d34a61d672337d1681b83bb90080e11 100644 (file)
@@ -1,4 +1,5 @@
 #include <ccan/talloc/talloc.h>
+#include <ccan/err/err.h>
 #include "tools.h"
 #include <assert.h>
 #include <string.h>
@@ -22,10 +23,19 @@ static unsigned int ccan_dir_prefix(const char *fulldir)
 
 const char *find_ccan_dir(const char *base)
 {
-       unsigned int prefix = ccan_dir_prefix(base);
+       static char *ccan_dir;
 
-       if (!prefix)
-               return NULL;
-
-       return talloc_strndup(NULL, base, prefix);
+       if (!ccan_dir) {
+               if (base[0] != '/') {
+                       const char *tmpctx = talloc_getcwd(NULL);
+                       find_ccan_dir(talloc_asprintf(tmpctx, "%s/%s",
+                                                     tmpctx, base));
+                       talloc_free(tmpctx);
+               } else {
+                       unsigned int prefix = ccan_dir_prefix(base);
+                       if (prefix)
+                               ccan_dir = talloc_strndup(NULL, base, prefix);
+               }
+       }
+       return ccan_dir;
 }
index ff786de88c70f201f17110ac83df342bc063c210..ac62ad3471a77fc376f2377317f56404d839db29 100644 (file)
@@ -208,7 +208,7 @@ struct doc_section *find_license_tag(const struct manifest *m)
        struct doc_section *d;
 
        list_for_each(get_ccan_file_docs(m->info_file), d, list) {
-               if (!streq(d->function, m->basename))
+               if (!streq(d->function, m->modname))
                        continue;
                if (streq(d->type, "license"))
                        return d;
index 72b3604efa45478c4f8d59110d92bc37bca9880a..e094f270b1461bdfa80512e38b62fb9295719117 100644 (file)
@@ -85,7 +85,7 @@ static void check_headers_no_cpp(struct manifest *m,
                   "#define using #DONT_USE_CPLUSPLUS_RESERVED_NAMES\n"
                   "#define virtual #DONT_USE_CPLUSPLUS_RESERVED_NAMES\n"
                   "#include <ccan/%s/%s.h>\n",
-                                  m->basename, m->basename);
+                                  m->modname, m->basename);
        if (write(fd, contents, strlen(contents)) != strlen(contents))
                err(1, "writing to temporary file %s", tmpsrc);
        close(fd);
index 2a47d0eb97fc7f3ded74a6ef01e676a1cd8fae75..83a19e2cea57ad041f5c71584a9eb5beb23b008d 100644 (file)
@@ -22,7 +22,7 @@ static bool has_dep(struct manifest *m, char **deps, bool *used,
        unsigned int i;
 
        /* We can include ourselves, of course. */
-       if (streq(depname + strlen("ccan/"), m->basename))
+       if (streq(depname + strlen("ccan/"), m->modname))
                return true;
 
        for (i = 0; deps[i]; i++) {
@@ -48,7 +48,7 @@ static bool check_dep_includes(struct manifest *m,
                char *mod;
                if (!strreg(f, lines[i],
                            "^[ \t]*#[ \t]*include[ \t]*[<\"]"
-                           "(ccan/+[^/]+)/", &mod))
+                           "(ccan/+.+)/+[^/]+.h", &mod))
                        continue;
 
                if (has_dep(m, deps, used, mod))
index b578d4b597b7f5b62d98dc5d6d5218b6be89a85b..3cfb9c4460161475e932de455f2e5bde96c0dff7 100644 (file)
@@ -47,7 +47,7 @@ static char *build_subdir_objs(struct manifest *m,
                        return talloc_asprintf(m,
                                               "Dependency %s"
                                               " did not build:\n%s",
-                                              m->basename, output);
+                                              m->modname, output);
                }
        }
        return NULL;
@@ -94,7 +94,7 @@ static void check_depends_built(struct manifest *m,
                                                               "Dependency %s"
                                                               " did not"
                                                               " build:\n%s",
-                                                              i->basename,
+                                                              i->modname,
                                                               errstr);
                                return;
                        }
index faa3b21d115b28fc31066d7456f9b0f5e3eefbee..b75ebefd5e18f0f831739a4589ae0680820fc028 100644 (file)
@@ -45,7 +45,7 @@ static void check_depends_built_without_features(struct manifest *m,
                                                               "Dependency %s"
                                                               " did not"
                                                               " build:\n%s",
-                                                              i->basename,
+                                                              i->modname,
                                                               errstr);
                                return;
                        }
index 76750fb1236f7bab79e7ff2a73412aa74185d919..3d50a063a243c857bd79179c21dae0eba118955d 100644 (file)
@@ -19,7 +19,7 @@ static bool have_dep(struct manifest *m, const char *dep)
        struct manifest *i;
 
        list_for_each(&m->deps, i, list)
-               if (streq(i->basename, dep + strlen("ccan/")))
+               if (streq(i->modname, dep + strlen("ccan/")))
                        return true;
 
        return false;
@@ -80,7 +80,7 @@ static void check_test_depends_exist(struct manifest *m,
        bool needs_tap;
 
        /* We may need libtap for testing, unless we're "tap" */
-       if (streq(m->basename, "tap")) {
+       if (streq(m->modname, "tap")) {
                needs_tap = false;
        } else if (list_empty(&m->run_tests) && list_empty(&m->api_tests)) {
                needs_tap = false;
index ac9476fd01bcb34843525fda34c781b0045aa89a..ce1d9769691d7ee6fa07736e33718f8deb2c55e5 100644 (file)
@@ -30,27 +30,27 @@ static void add_mod(struct manifest ***deps, struct manifest *m)
        (*deps)[num] = m;
 }
 
-static bool have_mod(struct manifest *deps[], const char *basename)
+static bool have_mod(struct manifest *deps[], const char *modname)
 {
        unsigned int i;
 
        for (i = 0; i < talloc_get_size(deps) / sizeof(*deps); i++)
-               if (strcmp(deps[i]->basename, basename) == 0)
+               if (strcmp(deps[i]->modname, modname) == 0)
                        return true;
        return false;
 }
 
-static void add_dep(struct manifest ***deps, const char *basename)
+static void add_dep(struct manifest ***deps, const char *modname)
 {
        unsigned int i;
        struct manifest *m;
        char *errstr;
 
-       if (have_mod(*deps, basename))
+       if (have_mod(*deps, modname))
                return;
 
        m = get_manifest(*deps, talloc_asprintf(*deps, "%s/ccan/%s",
-                                               ccan_dir, basename));
+                                               ccan_dir, modname));
        errstr = build_submodule(m, cflags, COMPILE_NORMAL);
        if (errstr)
                errx(1, "%s", errstr);
@@ -79,7 +79,7 @@ static struct manifest **get_example_deps(struct manifest *m,
        struct manifest **deps = talloc_array(f, struct manifest *, 0);
 
        /* This one for a start. */
-       add_dep(&deps, m->basename);
+       add_dep(&deps, m->modname);
 
        /* Other modules implied by includes. */
        for (lines = get_ccan_file_lines(f); *lines; lines++) {
@@ -362,7 +362,7 @@ static char *mangle(struct manifest *m, char **lines)
                              "#include <sys/stat.h>\n"
                              "#include <sys/types.h>\n"
                              "#include <unistd.h>\n",
-                             m->basename, m->basename);
+                             m->modname, m->basename);
 
        ret = talloc_asprintf_append(ret, "/* Useful dummy functions. */\n"
                                     "extern int somefunc(void);\n"
index bf8c9f2dad8e61e406c40b6399aeae98fa12129b..4e41d058d22a60fcf4edf8550aba0586c0d7bd33 100644 (file)
@@ -46,10 +46,10 @@ static void handle_idem(struct manifest *m, struct score *score)
                /* Main header gets CCAN_FOO_H, others CCAN_FOO_XXX_H */
                if (strstarts(e->file->name, m->basename)
                    || strlen(e->file->name) == strlen(m->basename) + 2)
-                       name = talloc_asprintf(score, "CCAN_%s_H", m->basename);
+                       name = talloc_asprintf(score, "CCAN_%s_H", m->modname);
                else
                        name = talloc_asprintf(score, "CCAN_%s_%s",
-                                              m->basename, e->file->name);
+                                              m->modname, e->file->name);
                fix_name(name);
 
                q = talloc_asprintf(score,
index 93954c76df5612b87ea62974481d6ec47e28c60b..0c0ed451494db5604e489fa036a55050360015b4 100644 (file)
@@ -47,7 +47,7 @@ static void create_info_template_doc(struct manifest *m, struct score *score)
                    " *\n"
                    " * Followed by an Example: section with a standalone\n"
                    " * (trivial and usually useless) program\n"
-                   " */\n", m->basename, m->basename) < 0) {
+                   " */\n", m->modname, m->basename) < 0) {
                unlink_noerr("_info.new");
                err(1, "Writing to _info.new to insert documentation");
        }
@@ -83,7 +83,7 @@ static void check_info_documentation_exists(struct manifest *m,
        score->pass = true;
 
        list_for_each(infodocs, d, list) {
-               if (!streq(d->function, m->basename))
+               if (!streq(d->function, m->modname))
                        continue;
                if (streq(d->type, "summary"))
                        summary = true;
index 330749ba46af0e076f91916c15cd6b4860a5b0e1..a667c0817e4e0c9cb10dcaa2ba7918f1a8526f2b 100644 (file)
@@ -68,7 +68,7 @@ static void create_info_template(struct manifest *m, struct score *score)
        if (!info)
                err(1, "Trying to create a template _info in %s", filename);
 
-       if (fprintf(info, template, m->basename) < 0) {
+       if (fprintf(info, template, m->modname) < 0) {
                unlink_noerr(filename);
                err(1, "Writing template into %s", filename);
        }
index 6517a7fc5d6973a0bdcad1e06351acc2f0d0e745..f04b4638025a723a87528410778fb1867c52adfa 100644 (file)
@@ -36,7 +36,7 @@ static void check_license_depends_compat(struct manifest *m,
                        score_file_error(score, i->info_file, 0,
                                         "Dependency ccan/%s has"
                                         " incompatible license '%s'",
-                                        i->basename,
+                                        i->modname,
                                         licenses[i->license].name);
                        score->pass = false;
                }
index 53071c6345178641ab017eb5157a7e26ef1ced6b..6305d61c02881a7fef67780d58067f1c80a2c9b0 100644 (file)
 #include <ccan/talloc/talloc.h>
 #include <ccan/str/str.h>
 
-static const char *expected_link(enum license license)
+/* We might need more ../ for nested modules. */
+static const char *link_prefix(struct manifest *m)
 {
+       char *prefix = talloc_strdup(m, "../../");
+       unsigned int i;
+
+       for (i = 0; i < strcount(m->modname, "/"); i++)
+               prefix = talloc_append_string(prefix, "../");
+
+       return talloc_append_string(prefix, "licenses/");
+}
+
+static const char *expected_link(const char *prefix, enum license license)
+{
+       const char *shortname;
+
        switch (license) {
        case LICENSE_LGPLv2_PLUS:
        case LICENSE_LGPLv2:
-               return "../../licenses/LGPL-2.1";
+               shortname = "LGPL-2.1";
+               break;
        case LICENSE_LGPLv3:
        case LICENSE_LGPL:
-               return "../../licenses/LGPL-3";
+               shortname = "LGPL-3";
+               break;
 
        case LICENSE_GPLv2_PLUS:
        case LICENSE_GPLv2:
-               return "../../licenses/GPL-2";
+               shortname = "GPL-2";
+               break;
 
        case LICENSE_GPLv3:
        case LICENSE_GPL:
-               return "../../licenses/GPL-3";
+               shortname = "GPL-3";
+               break;
 
        case LICENSE_BSD:
-               return "../../licenses/BSD-3CLAUSE";
+               shortname = "BSD-3CLAUSE";
+               break;
 
        case LICENSE_MIT:
-               return "../../licenses/BSD-MIT";
+               shortname = "BSD-MIT";
+               break;
 
        case LICENSE_CC0:
-               return "../../licenses/CC0";
+               shortname = "CC0";
+               break;
 
        default:
                return NULL;
        }
+
+       return talloc_append_string(talloc_strdup(prefix, prefix), shortname);
 }
 
 static void handle_license_link(struct manifest *m, struct score *score)
 {
        struct doc_section *d = find_license_tag(m);
+       const char *prefix = link_prefix(m);
        const char *link = talloc_asprintf(m, "%s/LICENSE", m->dir);
-       const char *ldest = expected_link(m->license);
+       const char *ldest = expected_link(prefix, m->license);
        char *q;
 
        printf(
        "Most modules want a copy of their license, so usually we create a\n"
-       "LICENSE symlink into ../../licenses to avoid too many copies.\n");
+       "LICENSE symlink into %s to avoid too many copies.\n", prefix);
 
        /* FIXME: make ask printf-like */
        q = talloc_asprintf(m, "Set up link to %s (license is %s)?",
@@ -73,6 +97,7 @@ static void check_has_license(struct manifest *m,
        char *license = talloc_asprintf(m, "%s/LICENSE", m->dir);
        const char *expected;
        struct doc_section *d;
+       const char *prefix = link_prefix(m);
 
        d = find_license_tag(m);
        if (!d) {
@@ -93,7 +118,7 @@ static void check_has_license(struct manifest *m,
        /* If they have a license tag at all, we pass. */
        score->pass = true;
 
-       expected = expected_link(m->license);
+       expected = expected_link(prefix, m->license);
 
        len = readlink(license, buf, sizeof(buf));
        if (len < 0) {
@@ -129,11 +154,10 @@ static void check_has_license(struct manifest *m,
 
        buf[len] = '\0';
 
-       if (!strstarts(buf, "../../licenses/")) {
+       if (!strstarts(buf, prefix)) {
                score->error = talloc_asprintf(score,
-                                              "Expected symlink to"
-                                              " ../../licenses/..."
-                                              " not %s", buf);
+                                              "Expected symlink into"
+                                              " %s not %s", prefix, buf);
                return;
        }
 
index b4a12e1349297a4330f2cae800c6d580e517232a..c6c51837a8f5833f2b7ce735d5d10c147a92f67d 100644 (file)
@@ -51,7 +51,7 @@ static void check_includes_build(struct manifest *m,
                err(1, "Creating temporary file %s", tmpsrc);
 
        contents = talloc_asprintf(tmpsrc, "#include <ccan/%s/%s.h>\n",
-                                  m->basename, m->basename);
+                                  m->modname, m->basename);
        if (write(fd, contents, strlen(contents)) != strlen(contents))
                err(1, "writing to temporary file %s", tmpsrc);
        close(fd);
index f039a1882eeaa0883f589f7614d130b523f20bd0..cdb01149d97f245a86262e0d7094b3568fe8adc2 100644 (file)
@@ -29,7 +29,7 @@ static void check_has_main_header(struct manifest *m,
        "You have no %s/%s.h header file.\n\n"
        "CCAN modules have a name, the same as the directory name.  They're\n"
        "expected to have an interface in the header of the same name.\n",
-                                      m->basename, m->basename);
+                                      m->modname, m->basename);
 }
 
 struct ccanlint main_header_exists = {
index d665ba7d6672f7a86849f6683686e6bb83fa42a3..5c25e6126589ebd0cadd01d15b4fd66e8a18e11c 100644 (file)
@@ -58,10 +58,9 @@ static void check_use_build(struct manifest *m,
 {
        char *contents;
        char *tmpfile, *cmdout;
-       char *basename = talloc_asprintf(m, "%s/example.c", m->dir);
        int fd;
 
-       tmpfile = temp_file(m, ".c", basename);
+       tmpfile = temp_file(m, ".c", "example.c");
 
        fd = open(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
        if (fd < 0)
@@ -73,7 +72,7 @@ static void check_use_build(struct manifest *m,
                                   "{\n"
                                   "    return 0;\n"
                                   "}\n",
-                                  m->basename, m->basename);
+                                  m->modname, m->basename);
        if (write(fd, contents, strlen(contents)) != strlen(contents))
                err(1, "Failure writing to temporary file %s", tmpfile);
        close(fd);
index 9aa6fd8432fa6a6c446f83875db46acc514c2286..c2fe1b6cc7c519e52d920ae5df14c510e8f42072 100644 (file)
@@ -112,7 +112,7 @@ static void build_objects_with_stringchecks(struct manifest *m,
                tmp = temp_file(score, ".c", i->fullname);
                tmpfd = start_file(tmp);
                line = talloc_asprintf(score, "#include <ccan/%s/%s.h>\n",
-                                      m->basename, m->basename);
+                                      m->modname, m->basename);
                write_str(tmpfd, line);
                close(tmpfd);
                test_compile(score, i, tmp, flags, &errors, &warnings);
index efa997536c969ee3373b4c6193664f99028bd9ed..a90ce0c021c71f3c10cfbe11d7e937f9e98fa55d 100644 (file)
@@ -69,12 +69,12 @@ static void handle_no_tests(struct manifest *m, struct score *score)
        if (!run)
                err(1, "Trying to create a test/run.c");
 
-       fprintf(run, "#include <ccan/%s/%s.h>\n", m->basename, m->basename);
+       fprintf(run, "#include <ccan/%s/%s.h>\n", m->modname, m->basename);
        if (!list_empty(&m->c_files)) {
                fputs("/* Include the C files directly. */\n", run);
                list_for_each(&m->c_files, i, list)
                        fprintf(run, "#include <ccan/%s/%s>\n",
-                               m->basename, i->name);
+                               m->modname, i->name);
        }
        fprintf(run, "%s",
                "#include <ccan/tap/tap.h>\n\n"
index 3dcd9d38e2c8cae54dc37867422cd6bc8b108cc4..a7c353c27d04571473808b67692219cc46cf2b12 100644 (file)
@@ -40,7 +40,7 @@ lines_from_cmd(const void *ctx, const char *format, ...)
  * temp_file helps here. */
 char *compile_info(const void *ctx, const char *dir)
 {
-       char *info_c_file, *info, *ccandir, *compiled, *output;
+       char *info_c_file, *info, *compiled, *output;
        size_t len;
        int fd;
 
@@ -59,12 +59,8 @@ char *compile_info(const void *ctx, const char *dir)
        if (close(fd) != 0)
                return NULL;
 
-       ccandir = talloc_dirname(ctx, dir);
-       if (strrchr(ccandir, '/'))
-               *strrchr(ccandir, '/') = '\0';
-
        compiled = temp_file(ctx, "", "info");
-       if (compile_and_link(ctx, info_c_file, ccandir, "",
+       if (compile_and_link(ctx, info_c_file, find_ccan_dir(dir), "",
                             CCAN_COMPILER, CCAN_CFLAGS " -I.", "",
                             compiled, &output))
                return compiled;
@@ -209,8 +205,7 @@ get_all_deps(const void *ctx, const char *dir, const char *style,
                        continue;
 
                subdir = talloc_asprintf(ctx, "%s/%s",
-                                        talloc_dirname(ctx, dir),
-                                        deps[i] + strlen("ccan/"));
+                                        find_ccan_dir(dir), deps[i]);
                newdeps = get_one(ctx, subdir, "depends", get_info);
 
                /* Should be short, so brute-force out dups. */
@@ -285,8 +280,7 @@ char **get_libs(const void *ctx, const char *dir, const char *style,
                                continue;
 
                        subdir = talloc_asprintf(ctx, "%s/%s",
-                                                talloc_dirname(ctx, dir),
-                                                deps[i] + strlen("ccan/"));
+                                                find_ccan_dir(dir), deps[i]);
 
                        newlibs = get_one_libs(ctx, subdir, get_info);
                        newlen = talloc_array_length(newlibs);
index 74643a04b994b61487f63cf7ba9786b37622d238..7788fd0766fe871df70651006c3b2a2d24019dc6 100644 (file)
@@ -71,7 +71,8 @@ static unsigned int is_summary_line(const char *line)
 {
        unsigned int id_len;
 
-       id_len = strspn(line, IDENT_CHARS" ");
+       /* We allow /, because it can be in (nested) module names. */
+       id_len = strspn(line, IDENT_CHARS" /");
        if (id_len == 0)
                return 0;
        if (strspn(line, " ") == id_len)
index 4cf540bd477bbabdc31e55e22503d1068170285d..cf4c987e956a261ea42772d16e3f1a5faab8d682 100644 (file)
@@ -239,6 +239,7 @@ struct manifest *get_manifest(const void *ctx, const char *dir)
        list_head_init(&m->deps);
        list_head_init(&m->test_deps);
 
+       /* Trim trailing /. */
        len = strlen(m->dir);
        while (len && m->dir[len-1] == '/')
                m->dir[--len] = '\0';
@@ -248,6 +249,9 @@ struct manifest *get_manifest(const void *ctx, const char *dir)
                errx(1, "I don't expect to be run from the root directory");
        m->basename++;
 
+       assert(strstarts(m->dir, find_ccan_dir(m->dir)));
+       m->modname = m->dir + strlen(find_ccan_dir(m->dir)) + strlen("ccan/");
+
        add_files(m, "");
 
        /* Nicer to run tests in a predictable order. */
index 04f88d9e084ee7f5e14397e1ba5e8596b7bd822e..3b6eb2077f4c87049d7d1df775c98198425f7dc3 100644 (file)
@@ -13,7 +13,9 @@ enum compile_type {
 
 struct manifest {
        char *dir;
-       /* The module name, ie. final element of dir name */
+       /* The name of the module, ie. elements of dir name after ccan/. */
+       char *modname;
+       /* The final element of dir name */
        char *basename;
        struct ccan_file *info_file;