Skip to content
This repository was archived by the owner on Jan 10, 2023. It is now read-only.

Commit b92776e

Browse files
author
Eric Crosson
committed
Add readme and license
complete implementation of subcommands
1 parent 921ef1e commit b92776e

File tree

11 files changed

+237
-126
lines changed

11 files changed

+237
-126
lines changed

cmd/add.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"fmt"
6+
"errors"
7+
"regexp"
8+
"strings"
9+
"path/filepath"
10+
11+
"github.com/urfave/cli"
12+
"github.com/codeskyblue/go-sh"
13+
"github.com/git-hook/git-ledger"
14+
)
15+
16+
// Get remote of the first remote listed by `git remote` for project.
17+
func getRemote(project string) string {
18+
session := sh.NewSession()
19+
session.SetDir(project)
20+
remote, err := session.Command("git", "remote").Command("head", "-n", "1").Output()
21+
// pipe makes this code unreachable
22+
if err != nil {
23+
panic(err)
24+
}
25+
return strings.TrimSpace(string(remote))
26+
}
27+
28+
// Get the slug of the first remote listed by `git remote` for project.
29+
func getSlug(project string) (string, error) {
30+
if !ledger.IsGitProject(project) {
31+
return "", errors.New(fmt.Sprintf("Cannot add %s: not a git project", project))
32+
}
33+
session := sh.NewSession()
34+
session.SetDir(project)
35+
out, err := session.Command("git", "remote", "get-url", getRemote(project)).Output()
36+
if err != nil {
37+
return "", err
38+
}
39+
output := strings.TrimSpace(string(out))
40+
reg := regexp.MustCompile(`[^/:]*/[^/:]*$`)
41+
res := reg.FindStringSubmatch(output)
42+
return res[0], nil
43+
}
44+
45+
// Add specified path to the ledger.
46+
func add(c *cli.Context) error {
47+
project := c.Args().First()
48+
49+
slug, err := getSlug(project)
50+
if err != nil {
51+
fmt.Fprintf(os.Stderr, "%s\n", err)
52+
return err
53+
}
54+
absolutePath, _ := filepath.Abs(project)
55+
56+
record := ledger.Record{Path: absolutePath, Slug: slug}
57+
record.RemoveFromLedger()
58+
record.AddToLedger()
59+
60+
return nil
61+
}

cmd/find.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"fmt"
6+
"path/filepath"
7+
8+
"github.com/urfave/cli"
9+
"github.com/git-hook/git-ledger"
10+
)
11+
12+
// Find path associated with specified path or slug from the ledger.
13+
func find(c *cli.Context) error {
14+
input := c.Args().First()
15+
16+
record, err := ledger.GetBySlug(input)
17+
if err != nil {
18+
absolutePath, _ := filepath.Abs(input)
19+
record, err = ledger.GetByPath(absolutePath)
20+
}
21+
if err != nil {
22+
fmt.Fprintf(os.Stderr, "%s\n", err)
23+
return err
24+
}
25+
fmt.Println(record.Path)
26+
27+
return nil
28+
}
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
package main
22

33
import (
4+
"os"
45
"fmt"
56

67
"github.com/urfave/cli"
7-
"github.com/git-hook/git-ledger/src/git-ledger"
8+
"github.com/git-hook/git-ledger"
89
)
910

11+
// List all records in the git-ledger.
1012
func ls(c *cli.Context) error {
1113
records, err := ledger.GetRecords()
1214
if err != nil {
13-
// TODO: stderr time
14-
// TODO exit code
15-
panic(err)
15+
fmt.Fprintf(os.Stderr, "%s", err)
16+
return err
1617
}
1718

1819
for _, rec := range records {
1920
fmt.Println(fmt.Sprintf("%s: %s", rec.Slug, rec.Path))
2021
}
21-
// TODO: handle no size, print "none" to stderr? if git does something similar
22+
23+
// Ledger is empty
24+
if len(records) == 0 {
25+
fmt.Fprintf(os.Stderr, "Ledger is empty\n")
26+
}
2227
return nil
2328
}

src/cmd/git-ledger/main.go renamed to cmd/main.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ func main () {
2121
{
2222
Name: "add",
2323
Usage: "Start tracking an existing repository.",
24-
ArgsUsage: "[<path>]",
24+
ArgsUsage: "[path]",
2525
Action: add,
2626
},
2727
{
2828
Name: "find",
2929
Usage: "Print the location of a tracked repository.",
30-
ArgsUsage: "[<path>]",
30+
ArgsUsage: "[path]",
3131
Action: find,
3232
},
3333
{
@@ -38,7 +38,7 @@ func main () {
3838
{
3939
Name: "rm",
4040
Usage: "Stop tracking an existing repository.",
41-
ArgsUsage: "[<path>]",
41+
ArgsUsage: "[path]",
4242
Action: rm,
4343
},
4444
}

cmd/rm.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"fmt"
6+
"path/filepath"
7+
8+
"github.com/urfave/cli"
9+
"github.com/git-hook/git-ledger"
10+
)
11+
12+
// Remove specified path or slug from the ledger.
13+
func rm(c *cli.Context) error {
14+
input := c.Args().First()
15+
16+
// Obtain record by slug or, if DNE, path
17+
record, err := ledger.GetBySlug(input)
18+
if err != nil {
19+
absolutePath, _ := filepath.Abs(input)
20+
record, err = ledger.GetByPath(absolutePath)
21+
}
22+
if err != nil {
23+
fmt.Fprintf(os.Stderr, "%s\n", err)
24+
return err
25+
}
26+
27+
err = record.RemoveFromLedger()
28+
if err != nil {
29+
fmt.Fprintf(os.Stderr, "%s\n", err)
30+
return err
31+
}
32+
33+
return nil
34+
}

src/git-ledger/ledger.go renamed to ledger.go

+37-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Package ledger provides primitives for operating on the user's
2+
// git-ledger.
13
package ledger
24

35
import (
@@ -12,22 +14,34 @@ import (
1214
"github.com/BurntSushi/toml"
1315
)
1416

17+
// Record entry in the git-ledger.
1518
type Record struct {
1619
Path string
1720
Slug string
1821
}
1922

20-
type Records struct {
23+
// Struct of Records, for toml parsing.
24+
type records struct {
2125
Record []Record
2226
}
2327

28+
// Get the path of the git-ledger.
2429
func Path() string {
2530
home, _ := pathutil.HomeDir()
2631
return path.Join(home, ".git-ledger")
2732
}
2833

34+
// Return true if dir contains a .git directory.
35+
func IsGitProject(dir string) bool {
36+
stat, err := os.Stat(path.Join(dir, ".git"))
37+
isProject := err == nil && stat.IsDir()
38+
return isProject
39+
}
40+
41+
42+
// Get a list of records currently in the git-ledger.
2943
func GetRecords() ([]Record, error) {
30-
var ledger Records
44+
var ledger records
3145

3246
b, err := ioutil.ReadFile(Path())
3347
if err != nil {
@@ -41,6 +55,7 @@ func GetRecords() ([]Record, error) {
4155
return ledger.Record, err
4256
}
4357

58+
// Look-up a record from the git-ledger by slug.
4459
func GetBySlug(slug string) (Record, error) {
4560
var match Record
4661

@@ -56,12 +71,29 @@ func GetBySlug(slug string) (Record, error) {
5671
return match, errors.New(fmt.Sprintf("Unknown project: %s", slug))
5772
}
5873

59-
// fixme: remove duplicated code
74+
// Look-up a record from the git-ledger by path.
75+
func GetByPath(path string) (Record, error) {
76+
var match Record
77+
78+
records, err := GetRecords()
79+
if err != nil {
80+
return match, err
81+
}
82+
for _, r := range records {
83+
if r.Path == path {
84+
return r, nil
85+
}
86+
}
87+
return match, errors.New(fmt.Sprintf("Unknown project: %s", path))
88+
}
89+
90+
// Return the current record as a toml string.
6091
func (r Record) String() string {
6192
return fmt.Sprintf("[[Record]]\npath = \"%s\"\nslug = \"%s\"\n\n", r.Path, r.Slug)
6293
}
6394

64-
// comparison by Path
95+
// Remove record from the git-ledger. Will remove all records
96+
// matching this records path from the ledger.
6597
func (r Record) RemoveFromLedger() error {
6698
records, err := GetRecords()
6799
if err != nil {
@@ -79,6 +111,7 @@ func (r Record) RemoveFromLedger() error {
79111
return nil
80112
}
81113

114+
// Add record to the git-ledger.
82115
func (r Record) AddToLedger() {
83116
f, err := os.OpenFile(Path(), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
84117
if err != nil {

license

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) Eric Crosson <esc@ericcrosson.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

readme.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# git-ledger
2+
3+
> Track your local git clones
4+
5+
**git-ledger** acts as a simple key-value store, remembering the
6+
location of git-repositories on local filesystems.
7+
8+
## Install
9+
10+
WIP
11+
```bash
12+
go get github.com/git-hook/git-ledger
13+
cd $GOPATH/src/github.com/git-hook/git-ledger
14+
go build .
15+
go get .
16+
```
17+
18+
## API
19+
20+
### add [path-or-slug]
21+
22+
Start tracking an existing repository.
23+
24+
### find [path-or-slug]
25+
26+
Print the location of a tracked repository.
27+
28+
### ls
29+
30+
Print all tracked repositories.
31+
32+
### rm [path-or-slug]
33+
34+
Stop tracking an existing repository.
35+
36+
## Related
37+
38+
- [grit](https://github.com/jmalloc/grit)
39+
40+
## License
41+
42+
MIT © Eric Crosson

0 commit comments

Comments
 (0)