diff --git a/README.md b/README.md index d2394b1..3ffdd94 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,9 @@ Remove a remote. ### `Repo#status(callback)` Uses `--porcelain` to parse repository status in a way that is agnostic of system language. The callback receives `(err, status)`. See below for a definition of what `status` is. +### `Repo#config(callback)` +`git config` parsed as a simple, one-level object. The callback receives `(err, config)`. + ### `Repo#create_branch(name, callback)` Create a new branch with `name`, and call the callback when complete with an error, if one occurred. @@ -227,6 +230,10 @@ The callback receives `(err, actor)`. ### `Tag#tag_date(callback)` The callback receives `(err, date)`. +## Config +### `Config#items` +`Object` - The keys are dotted precisely as the console output from `git config`. E.g., `{'user.name': 'John Doe'}` + ## Status ### `Status#clean` `Boolean` @@ -304,5 +311,3 @@ Get the url the submodule points to. # License See LICENSE. - - diff --git a/src/config.coffee b/src/config.coffee new file mode 100644 index 0000000..04b5dd6 --- /dev/null +++ b/src/config.coffee @@ -0,0 +1,17 @@ +module.exports = C = (repo, callback) -> + repo.git "config", {list: true}, (err, stdout, stderr) -> + config = new Config repo + config.parse stdout + callback err, config + +C.Config = class Config + constructor: (@repo) -> + + # Internal: Parse the config from stdout of a `git config` command + parse: (text)-> + @items = {} + for line in text.split("\n") + if line.length == 0 + continue + [key, value] = line.split('=') + @items[key] = value diff --git a/src/diff.coffee b/src/diff.coffee index 96a969f..0d21c86 100644 --- a/src/diff.coffee +++ b/src/diff.coffee @@ -22,7 +22,7 @@ module.exports = class Diff diffs = [] while lines.length && lines[0] - [m, a_path, b_path] = ///^diff\s--git\sa/(.+?)\sb/(.+)$///.exec lines.shift() + [m, a_path, b_path] = ///^diff\s--git\s"?a/(.+?)"?\s"?b/(.+)"?$///.exec lines.shift() if /^old mode/.test lines[0] [m, a_mode] = /^old mode (\d+)/.exec lines.shift() diff --git a/src/git.coffee b/src/git.coffee index e177c0f..cb4e864 100644 --- a/src/git.coffee +++ b/src/git.coffee @@ -3,7 +3,7 @@ fs = require 'fs' module.exports = Git = (git_dir, dot_git) -> dot_git ||= "#{git_dir}/.git" - + git = (command, options, args, callback) -> [callback, args] = [args, callback] if !callback [callback, options] = [options, callback] if !callback @@ -15,26 +15,26 @@ module.exports = Git = (git_dir, dot_git) -> bash = "#{Git.bin} #{command} #{options} #{args}" exec bash, {cwd: git_dir}, callback return bash - - + + # Public: Get a list of the remote names. - # + # # callback - Receives `(err, names)`. - # + # git.list_remotes = (callback) -> fs.readdir "#{dot_git}/refs/remotes", (err, files) -> callback err, (files || []) - - + + # Public: Get the ref data string. - # + # # type - Such as `remote` or `tag`. # callback - Receives `(err, stdout)`. - # + # git.refs = (type, options, callback) -> [callback, options] = [options, callback] if !callback prefix = "refs/#{type}s/" - + git "show-ref", (err, text) -> matches = [] for line in (text || "").split("\n") @@ -43,7 +43,7 @@ module.exports = Git = (git_dir, dot_git) -> if name.substr(0, prefix.length) == prefix matches.push "#{name.substr(prefix.length)} #{id}" return callback err, matches.join("\n") - + return git diff --git a/src/repo.coffee b/src/repo.coffee index 7922dfd..94870f4 100644 --- a/src/repo.coffee +++ b/src/repo.coffee @@ -2,6 +2,7 @@ _ = require 'underscore' cmd = require './git' Actor = require './actor' Commit = require './commit' +Config = require './config' Tree = require './tree' Diff = require './diff' Tag = require './tag' @@ -184,6 +185,9 @@ module.exports = class Repo status: (callback) -> return Status(this, callback) + config: (callback) -> + return Config(this, callback) + # Public: Get the repository's tags. # diff --git a/test/config.test.coffee b/test/config.test.coffee new file mode 100644 index 0000000..0c9c647 --- /dev/null +++ b/test/config.test.coffee @@ -0,0 +1,36 @@ +should = require 'should' +Config = require '../src/config' + +GIT_CONFIG = """ +user.name=John Doe +user.email=john.doe@git-scm.com +core.editor=pico +""" + +GIT_CONFIG_DUPLICATE_KEYS = """ +user.name=John Doe +user.email=john.doe@git-scm.com +core.editor=pico +user.email=john.doe@github.com +core.editor=emacs +""" + +describe "Config", -> + describe "()", -> + describe "when there are no overlapping keys", -> + config = new Config.Config 'mock repo' + config.parse GIT_CONFIG + + it "read the keys and values", -> + config.items['user.name'].should.equal 'John Doe' + config.items['user.email'].should.equal 'john.doe@git-scm.com' + config.items['core.editor'].should.equal 'pico' + + describe "with overlapping keys", -> + config = new Config.Config 'mock repo' + config.parse GIT_CONFIG_DUPLICATE_KEYS + + it "read the keys and values", -> + config.items['user.name'].should.equal 'John Doe' + config.items['user.email'].should.equal 'john.doe@github.com' + config.items['core.editor'].should.equal 'emacs' diff --git a/test/status.test.coffee b/test/status.test.coffee index b9d625d..d16b4de 100644 --- a/test/status.test.coffee +++ b/test/status.test.coffee @@ -22,10 +22,10 @@ describe "Status", -> repo = fixtures.status status = new Status.Status repo status.parse GIT_STATUS_CLEAN - + it "is clean", -> status.clean.should.be.true - + describe "when there are changes", -> repo = fixtures.status status = new Status.Status repo @@ -37,25 +37,25 @@ describe "Status", -> repo = fixtures.status status = new Status.Status repo status.parse GIT_STATUS - + it "has a modified staged file", -> status.files["file.txt"].staged.should.be.true status.files["file.txt"].type.should.eql "M" status.files["file.txt"].tracked.should.be.true - + it "has a modified unstaged file", -> status.files["cheese.txt"].staged.should.be.false status.files["cheese.txt"].type.should.eql "M" status.files["cheese.txt"].tracked.should.be.true - + it "has a deleted file", -> status.files["crackers.txt"].staged.should.be.true status.files["crackers.txt"].type.should.eql "D" status.files["crackers.txt"].tracked.should.be.true - + it "has an untracked file", -> status.files["pickles.txt"].tracked.should.be.false should.not.exist status.files["pickles.txt"].type - + it "is not clean", -> status.clean.should.be.false