packages feed

projectroot (empty) → 0.1.0.0

raw patch · 8 files changed

+557/−0 lines, 8 filesdep +basedep +directorysetup-changed

Dependencies added: base, directory

Files

+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2015 Pedro Tacla Yamada++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ projectroot.cabal view
@@ -0,0 +1,27 @@+name:                projectroot+version:             0.1.0.0+synopsis:            Bindings to the projectroot C logic+description: Simple way of finding the root of a project given an+             entry-point. This module provides bindings to the+             <https://github.com/yamadapc/projectroot projectroot> C library+homepage:            https://gitlab.com/yamadapc/haskell-projectroot+license:             MIT+license-file:        LICENSE+author:              Pedro Tacla Yamada+maintainer:          tacla.yamada@gmail.com+copyright:           Copyright (c) 2015 Pedro Tacla Yamada+category:            System+build-type:          Simple+cabal-version:       >=1.10++library+  exposed-modules:     System.Directory.ProjectRoot+  build-depends:       base >=4.8 && <4.9+                     , directory+  hs-source-dirs:      src+  default-language:    Haskell2010+  c-sources:           ./projectroot/libprojectroot.c+                     , ./projectroot/deps/commander/commander.c+  install-includes:    ./projectroot/libprojectroot.h+                     , ./projectroot/deps/commander/commander.h+  include-dirs:        .
+ projectroot/deps/commander/commander.c view
@@ -0,0 +1,269 @@++//+// commander.c+//+// Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>+//++#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <assert.h>+#include "commander.h"++/*+ * Output error and exit.+ */++static void+error(char *msg) {+  fprintf(stderr, "%s\n", msg);+  exit(1);+}++/*+ * Output command version.+ */++static void+command_version(command_t *self) {+  printf("%s\n", self->version);+  command_free(self);+  exit(0);+}++/*+ * Output command help.+ */++void+command_help(command_t *self) {+  printf("\n");+  printf("  Usage: %s %s\n", self->name, self->usage);+  printf("\n");+  printf("  Options:\n");+  printf("\n");++  int i;+  for (i = 0; i < self->option_count; ++i) {+    command_option_t *option = &self->options[i];+    printf("    %s, %-25s %s\n"+      , option->small+      , option->large_with_arg+      , option->description);+  }++  printf("\n");+  command_free(self);+  exit(0);+}++/*+ * Initialize with program `name` and `version`.+ */++void+command_init(command_t *self, const char *name, const char *version) {+  self->arg = NULL;+  self->name = name;+  self->version = version;+  self->option_count = self->argc = 0;+  self->usage = "[options]";+  self->nargv = NULL;+  command_option(self, "-V", "--version", "output program version", command_version);+  command_option(self, "-h", "--help", "output help information", command_help);+}++/*+ * Free up commander after use.+ */++void+command_free(command_t *self) {+  int i;++  for (i = 0; i < self->option_count; ++i) {+    command_option_t *option = &self->options[i];+    free(option->argname);+    free(option->large);+  }++  if (self->nargv) {+    for (i = 0; self->nargv[i]; ++i) {+      free(self->nargv[i]);+    }+    free(self->nargv);+  }+}++/*+ * Parse argname from `str`. For example+ * Take "--required <arg>" and populate `flag`+ * with "--required" and `arg` with "<arg>".+ */++static void+parse_argname(const char *str, char *flag, char *arg) {+  int buffer = 0;+  size_t flagpos = 0;+  size_t argpos = 0;+  size_t len = strlen(str);+  size_t i;++  for (i = 0; i < len; ++i) {+    if (buffer || '[' == str[i] || '<' == str[i]) {+      buffer = 1;+      arg[argpos++] = str[i];+    } else {+      if (' ' == str[i]) continue;+      flag[flagpos++] = str[i];+    }+  }++  arg[argpos] = '\0';+  flag[flagpos] = '\0';+}++/*+ * Normalize the argument vector by exploding+ * multiple options (if any). For example+ * "foo -abc --scm git" -> "foo -a -b -c --scm git"+ */++static char **+normalize_args(int *argc, char **argv) {+  int size = 0;+  int alloc = *argc + 1;+  char **nargv = malloc(alloc * sizeof(char *));+  int i;++  for (i = 0; argv[i]; ++i) {+    const char *arg = argv[i];+    size_t len = strlen(arg);++    // short flag+    if (len > 2 && '-' == arg[0] && !strchr(arg + 1, '-')) {+      alloc += len - 2;+      nargv = realloc(nargv, alloc * sizeof(char *));+      for (size_t j = 1; j < len; ++j) {+        nargv[size] = malloc(3);+        sprintf(nargv[size], "-%c", arg[j]);+        size++;+      }+      continue;+    }++    // regular arg+    nargv[size] = malloc(len + 1);+    strcpy(nargv[size], arg);+    size++;+  }++  nargv[size] = NULL;+  *argc = size;+  return nargv;+}++/*+ * Define an option.+ */++void+command_option(command_t *self, const char *small, const char *large, const char *desc, command_callback_t cb) {+  if (self->option_count == COMMANDER_MAX_OPTIONS) {+    command_free(self);+    error("Maximum option definitions exceeded");+  }+  int n = self->option_count++;+  command_option_t *option = &self->options[n];+  option->cb = cb;+  option->small = small;+  option->description = desc;+  option->required_arg = option->optional_arg = 0;+  option->large_with_arg = large;+  option->argname = malloc(strlen(large) + 1);+  assert(option->argname);+  option->large = malloc(strlen(large) + 1);+  assert(option->large);+  parse_argname(large, option->large, option->argname);+  if ('[' == option->argname[0]) option->optional_arg = 1;+  if ('<' == option->argname[0]) option->required_arg = 1;+}++/*+ * Parse `argv` (internal).+ * Input arguments should be normalized first+ * see `normalize_args`.+ */++static void+command_parse_args(command_t *self, int argc, char **argv) {+  int literal = 0;+  int i, j;++  for (i = 1; i < argc; ++i) {+    const char *arg = argv[i];+    for (j = 0; j < self->option_count; ++j) {+      command_option_t *option = &self->options[j];++      // match flag+      if (!strcmp(arg, option->small) || !strcmp(arg, option->large)) {+        self->arg = NULL;++        // required+        if (option->required_arg) {+          arg = argv[++i];+          if (!arg || '-' == arg[0]) {+            fprintf(stderr, "%s %s argument required\n", option->large, option->argname);+            command_free(self);+            exit(1);+          }+          self->arg = arg;+        }++        // optional+        if (option->optional_arg) {+          if (argv[i + 1] && '-' != argv[i + 1][0]) {+            self->arg = argv[++i];+          }+        }++        // invoke callback+        option->cb(self);+        goto match;+      }+    }++    // --+    if ('-' == arg[0] && '-' == arg[1] && 0 == arg[2]) {+      literal = 1;+      goto match;+    }++    // unrecognized+    if ('-' == arg[0] && !literal) {+      fprintf(stderr, "unrecognized flag %s\n", arg);+      command_free(self);+      exit(1);+    }++    int n = self->argc++;+    if (n == COMMANDER_MAX_ARGS) {+      command_free(self);+      error("Maximum number of arguments exceeded");+    }+    self->argv[n] = (char *) arg;+    match:;+  }+}++/*+ * Parse `argv` (public).+ */++void+command_parse(command_t *self, int argc, char **argv) {+  self->nargv = normalize_args(&argc, argv);+  command_parse_args(self, argc, self->nargv);+  self->argv[self->argc] = NULL;+}
+ projectroot/deps/commander/commander.h view
@@ -0,0 +1,88 @@++//+// commander.h+//+// Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>+//++#ifndef COMMANDER_H+#define COMMANDER_H++/*+ * Max options that can be defined.+ */++#ifndef COMMANDER_MAX_OPTIONS+#define COMMANDER_MAX_OPTIONS 32+#endif++/*+ * Max arguments that can be passed.+ */++#ifndef COMMANDER_MAX_ARGS+#define COMMANDER_MAX_ARGS 32+#endif++/*+ * Command struct.+ */++struct command;++/*+ * Option callback.+ */++typedef void (* command_callback_t)(struct command *self);++/*+ * Command option.+ */++typedef struct {+  int optional_arg;+  int required_arg;+  char *argname;+  char *large;+  const char *small;+  const char *large_with_arg;+  const char *description;+  command_callback_t cb;+} command_option_t;++/*+ * Command.+ */++typedef struct command {+  void *data;+  const char *usage;+  const char *arg;+  const char *name;+  const char *version;+  int option_count;+  command_option_t options[COMMANDER_MAX_OPTIONS];+  int argc;+  char *argv[COMMANDER_MAX_ARGS];+  char **nargv;+} command_t;++// prototypes++void+command_init(command_t *self, const char *name, const char *version);++void+command_free(command_t *self);++void+command_help(command_t *self);++void+command_option(command_t *self, const char *small, const char *large, const char *desc, command_callback_t cb);++void+command_parse(command_t *self, int argc, char **argv);++#endif /* COMMANDER_H */
+ projectroot/libprojectroot.c view
@@ -0,0 +1,90 @@+#include <dirent.h>+#include <glob.h>+#include <libgen.h>+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <unistd.h>+#include "libprojectroot.h"++int weight_mode_on = 0;+int verbose_on = 0;++static const char* const candidates[] = {+  ".git",+  ".hg",+  ".fslckout",+  ".bzr",+  "_darcs",+  ".svn",+  "CVS",+  "rebar.config",+  "project.clj",+  "SConstruct",+  "pom.xml",+  "build.sbt",+  "build.gradle",+  "Gemfile",+  "requirements.txt",+  "tox.ini",+  "package.json",+  "node_modules",+  "gulpfile.js",+  "Gruntfile.js",+  "bower.json",+  "composer.json",+  "Cargo.toml",+  "stack.yaml",+  ".cabal-sandbox",+  "*.cabal",+  "mix.exs",+};++int is_project_root(char* cdt) {+  char pattern[1024];+  glob_t res;+  size_t cdt_size = strlen(cdt);++  strcpy(pattern, cdt);+  strcat(pattern, "/");++  for(int i = 0; i < N_CANDIDATES; i++) {+    strcat(pattern, candidates[i]);+    if(verbose_on) fprintf(stderr, "Matching: %s ~= %s\n", cdt, pattern);+    if(glob(pattern, GLOB_NOSORT, NULL, &res) == 0) {+      if(verbose_on) fprintf(stderr, "--> Matched (weight %d)\n", N_CANDIDATES - i + 1);+      return N_CANDIDATES - i + 1;+    }+    pattern[cdt_size + 1] = 0;+  }++  return 0;+}++char* find_project_root_weighted(char* cwd) {+  char* cdt = cwd;+  char* best_cdt = malloc(sizeof(char) * 1024);+  int best_cdt_weight = 0;+  int cdt_weight;++  while(strcmp(cdt, "/") != 0) {+    if((cdt_weight = is_project_root(cdt)) && cdt_weight > best_cdt_weight) {+      best_cdt_weight = cdt_weight;+      strcpy(best_cdt, cdt);+    }+    cdt = dirname(cdt);+  }++  return best_cdt;+}++char* find_project_root(char* cwd) {+  char* cdt = cwd;++  while(strcmp(cdt, "/") != 0) {+    if(is_project_root(cdt)) return cdt;+    cdt = dirname(cdt);+  }++  return NULL;+}
+ projectroot/libprojectroot.h view
@@ -0,0 +1,16 @@+#include <dirent.h>+#include <glob.h>+#include <libgen.h>+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <unistd.h>++#define N_CANDIDATES 26++int weight_mode_on;+int verbose_on;++int is_project_root(char* cdt);+char* find_project_root_weighted(char* cwd);+char* find_project_root(char* cwd);
+ src/System/Directory/ProjectRoot.hs view
@@ -0,0 +1,45 @@+-- |+-- Module: System.Directory.ProjectRoot+-- Description: Find the root of a project+-- Copyright: (c) Pedro Tacla Yamada, 2015+-- License: MIT+-- Maintainer: tacla.yamada@gmail.com+-- Stability: Stable+-- Portability: POSIX+--+-- Simple way of finding the root of a project given an entry-point.+-- This module provides bindings to the <https://github.com/yamadapc/projectroot projectroot> C library+module System.Directory.ProjectRoot+  where++import           Control.Monad    ((<=<), (>=>))+import           Foreign.C+import           System.Directory (getCurrentDirectory)++-- * Haskell Wrappers++-- |+-- Find the project root given an entry point+getProjectRoot :: FilePath -> IO FilePath+getProjectRoot = (find_project_root <=< newCString) >=> peekCString++-- |+-- Find the weighted project root given an entry point+getProjectRootWeighted :: FilePath -> IO FilePath+getProjectRootWeighted = (find_project_root_weighted <=< newCString) >=>+                         peekCString++-- |+-- Find the project root of the current directory+getProjectRootCurrent :: IO FilePath+getProjectRootCurrent = getCurrentDirectory >>= getProjectRoot++-- |+-- Find the weighted project root of the current directory+getProjectRootWeightedCurrent :: IO FilePath+getProjectRootWeightedCurrent = getCurrentDirectory >>= getProjectRootWeighted++-- * C functions++foreign import ccall "find_project_root" find_project_root :: CString -> IO CString+foreign import ccall "find_project_root_weighted" find_project_root_weighted :: CString -> IO CString