Print this page
5292 findunref is both slow and broken
@@ -51,34 +51,34 @@
unsigned int npath;
unsigned int maxpaths;
} pnset_t;
/*
- * Data associated with the current Mercurial manifest.
+ * Data associated with the current SCM manifest.
*/
-typedef struct hgdata {
+typedef struct scmdata {
pnset_t *manifest;
- char hgpath[MAXPATHLEN];
+ char metapath[MAXPATHLEN];
char root[MAXPATHLEN];
unsigned int rootlen;
boolean_t rootwarn;
-} hgdata_t;
+} scmdata_t;
/*
* Hooks used to check if a given unreferenced file is known to an SCM
- * (currently Mercurial and TeamWare).
+ * (currently Git, Mercurial and TeamWare).
*/
typedef int checkscm_func_t(const char *, const struct FTW *);
typedef void chdirscm_func_t(const char *);
typedef struct {
const char *name;
checkscm_func_t *checkfunc;
chdirscm_func_t *chdirfunc;
} scm_t;
-static checkscm_func_t check_tw, check_hg, check_git;
+static checkscm_func_t check_tw, check_scmdata;
static chdirscm_func_t chdir_hg, chdir_git;
static int pnset_add(pnset_t *, const char *);
static int pnset_check(const pnset_t *, const char *);
static void pnset_empty(pnset_t *);
static void pnset_free(pnset_t *);
@@ -88,19 +88,18 @@
static void die(const char *, ...);
static const scm_t scms[] = {
{ "tw", check_tw, NULL },
{ "teamware", check_tw, NULL },
- { "hg", check_hg, chdir_hg },
- { "mercurial", check_hg, chdir_hg },
- { "git", check_git, chdir_git },
+ { "hg", check_scmdata, chdir_hg },
+ { "mercurial", check_scmdata, chdir_hg },
+ { "git", check_scmdata, chdir_git },
{ NULL, NULL, NULL }
};
static const scm_t *scm;
-static hgdata_t hgdata;
-static pnset_t *gitmanifest = NULL;
+static scmdata_t scmdata;
static time_t tstamp; /* timestamp to compare files to */
static pnset_t *exsetp; /* pathname globs to ignore */
static const char *progname;
int
@@ -191,11 +190,11 @@
/*
* Load and return a pnset for the manifest for the Mercurial repo at `hgroot'.
*/
static pnset_t *
-load_manifest(const char *hgroot)
+hg_manifest(const char *hgroot)
{
FILE *fp = NULL;
char *hgcmd = NULL;
char *newline;
pnset_t *pnsetp;
@@ -229,134 +228,149 @@
free(hgcmd);
pnset_free(pnsetp);
return (NULL);
}
-static void
-chdir_git(const char *path)
+/*
+ * Load and return a pnset for the manifest for the Git repo at `gitroot'.
+ */
+static pnset_t *
+git_manifest(const char *gitroot)
{
FILE *fp = NULL;
char *gitcmd = NULL;
char *newline;
- char fn[MAXPATHLEN];
pnset_t *pnsetp;
+ char path[MAXPATHLEN];
pnsetp = calloc(sizeof (pnset_t), 1);
- if ((pnsetp == NULL) ||
- (asprintf(&gitcmd, "git ls-files %s", path) == -1))
+ if (pnsetp == NULL ||
+ asprintf(&gitcmd, "git --git-dir=%s/.git ls-files", gitroot) == -1)
goto fail;
- if ((fp = popen(gitcmd, "r")) == NULL)
+ fp = popen(gitcmd, "r");
+ if (fp == NULL)
goto fail;
- while (fgets(fn, sizeof (fn), fp) != NULL) {
- if ((newline = strrchr(fn, '\n')) != NULL)
+ while (fgets(path, sizeof (path), fp) != NULL) {
+ newline = strrchr(path, '\n');
+ if (newline != NULL)
*newline = '\0';
- if (pnset_add(pnsetp, fn) == 0)
+ if (pnset_add(pnsetp, path) == 0)
goto fail;
}
(void) pclose(fp);
free(gitcmd);
- gitmanifest = pnsetp;
- return;
+ return (pnsetp);
fail:
- warn("cannot load git manifest");
+ warn("cannot load git manifest at %s", gitroot);
if (fp != NULL)
(void) pclose(fp);
- if (pnsetp != NULL)
- free(pnsetp);
- if (gitcmd != NULL)
free(gitcmd);
+ pnset_free(pnsetp);
+ return (NULL);
}
/*
* If necessary, change our active manifest to be appropriate for `path'.
*/
static void
-chdir_hg(const char *path)
+chdir_scmdata(const char *path, const char *meta,
+ pnset_t *(*manifest_func)(const char *path))
{
- char hgpath[MAXPATHLEN];
+ char scmpath[MAXPATHLEN];
char basepath[MAXPATHLEN];
char *slash;
- (void) snprintf(hgpath, MAXPATHLEN, "%s/.hg", path);
+ (void) snprintf(scmpath, MAXPATHLEN, "%s/%s", path, meta);
/*
* Change our active manifest if any one of the following is true:
*
- * 1. No manifest is loaded. Find the nearest hgroot to load from.
+ * 1. No manifest is loaded. Find the nearest SCM root to load from.
*
* 2. A manifest is loaded, but we've moved into a directory with
- * its own hgroot (e.g., usr/closed). Load from its hgroot.
+ * its own metadata directory (e.g., usr/closed). Load from its
+ * root.
*
* 3. A manifest is loaded, but no longer applies (e.g., the manifest
* under usr/closed is loaded, but we've moved to usr/src).
*/
- if (hgdata.manifest == NULL ||
- strcmp(hgpath, hgdata.hgpath) != 0 && access(hgpath, X_OK) == 0 ||
- strncmp(path, hgdata.root, hgdata.rootlen - 1) != 0) {
- pnset_free(hgdata.manifest);
- hgdata.manifest = NULL;
+ if (scmdata.manifest == NULL ||
+ (strcmp(scmpath, scmdata.metapath) != 0 &&
+ access(scmpath, X_OK) == 0) ||
+ strncmp(path, scmdata.root, scmdata.rootlen - 1) != 0) {
+ pnset_free(scmdata.manifest);
+ scmdata.manifest = NULL;
(void) strlcpy(basepath, path, MAXPATHLEN);
/*
- * Walk up the directory tree looking for .hg subdirectories.
+ * Walk up the directory tree looking for metadata
+ * subdirectories.
*/
- while (access(hgpath, X_OK) == -1) {
+ while (access(scmpath, X_OK) == -1) {
slash = strrchr(basepath, '/');
if (slash == NULL) {
- if (!hgdata.rootwarn) {
- warn("no hg root for \"%s\"\n", path);
- hgdata.rootwarn = B_TRUE;
+ if (!scmdata.rootwarn) {
+ warn("no metadata directory "
+ "for \"%s\"\n", path);
+ scmdata.rootwarn = B_TRUE;
}
return;
}
*slash = '\0';
- (void) snprintf(hgpath, MAXPATHLEN, "%s/.hg", basepath);
+ (void) snprintf(scmpath, MAXPATHLEN, "%s/%s", basepath,
+ meta);
}
/*
- * We found a directory with an .hg subdirectory; record it
- * and load its manifest.
+ * We found a directory with an SCM metadata directory; record
+ * it and load its manifest.
*/
- (void) strlcpy(hgdata.hgpath, hgpath, MAXPATHLEN);
- (void) strlcpy(hgdata.root, basepath, MAXPATHLEN);
- hgdata.manifest = load_manifest(hgdata.root);
+ (void) strlcpy(scmdata.metapath, scmpath, MAXPATHLEN);
+ (void) strlcpy(scmdata.root, basepath, MAXPATHLEN);
+ scmdata.manifest = manifest_func(scmdata.root);
/*
- * The logic in check_hg() depends on hgdata.root having a
- * single trailing slash, so only add it if it's missing.
+ * The logic in check_scmdata() depends on scmdata.root having
+ * a single trailing slash, so only add it if it's missing.
*/
- if (hgdata.root[strlen(hgdata.root) - 1] != '/')
- (void) strlcat(hgdata.root, "/", MAXPATHLEN);
- hgdata.rootlen = strlen(hgdata.root);
+ if (scmdata.root[strlen(scmdata.root) - 1] != '/')
+ (void) strlcat(scmdata.root, "/", MAXPATHLEN);
+ scmdata.rootlen = strlen(scmdata.root);
}
}
+static void
+chdir_git(const char *path)
+{
+ chdir_scmdata(path, ".git", git_manifest);
+}
+
/*
- * Check if a file is under Mercurial control by checking against the manifest.
+ * If necessary, change our active manifest to be appropriate for `path'.
*/
+static void
+chdir_hg(const char *path)
+{
+ chdir_scmdata(path, ".hg", hg_manifest);
+}
+
/* ARGSUSED */
static int
-check_hg(const char *path, const struct FTW *ftwp)
+check_scmdata(const char *path, const struct FTW *ftwp)
{
/*
* The manifest paths are relative to the manifest root; skip past it.
*/
- path += hgdata.rootlen;
+ path += scmdata.rootlen;
- return (hgdata.manifest != NULL && pnset_check(hgdata.manifest, path));
-}
-/* ARGSUSED */
-static int
-check_git(const char *path, const struct FTW *ftwp)
-{
- path += 2; /* Skip "./" */
- return (gitmanifest != NULL && pnset_check(gitmanifest, path));
+ return (scmdata.manifest != NULL && pnset_check(scmdata.manifest,
+ path));
}
/*
* Check if a file is under TeamWare control by checking for its corresponding
* SCCS "s-dot" file.