Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions cmd/commands/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,31 @@ import (
"mgit/cmd/stage"
"mgit/cmd/storage"
"mgit/cmd/structures/blob"
"mgit/cmd/structures/commit"
"mgit/cmd/utils"
"os"
)

func Add(path string) {
// Should call this only if the file doesn't exist
func addRemovedFile(path string) {
tracked := commit.HeadTrackedFilesTree()

trackedMap := utils.StringSliceMap(tracked)

if _, found := trackedMap[path]; !found {
fmt.Println(path + " doesn't exist")
return
}

manager := stage.BlankManager()
manager.StageDeleted(path)
manager.Write()
fmt.Println("Added removed file ", path)
}

func addSingle(path string) {
if _, err := os.Stat(path); os.IsNotExist(err) {
fmt.Printf("%s doesn't exist\n", path)
addRemovedFile(path)
return
}

Expand All @@ -24,5 +43,14 @@ func Add(path string) {
blob := blob.CreateBlob(file)
storage.Create(blob.Hash, blob.Content)

stage.AddFile(path, blob.Hash)
stageManager := stage.BlankManager()
stageManager.Stage(path, blob.Hash)

stageManager.Write()
}

func Add(paths ...string) {
for _, path := range paths {
addSingle(path)
}
}
24 changes: 23 additions & 1 deletion cmd/commands/add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ func TestModifyAndStage(t *testing.T) {

commands.Add("./file_to_be_staged")

stageFiles := stage.GetFiles()
manager := stage.Load()
stageFiles := manager.AllObjects()

if len(stageFiles) != 1 {
t.Fatalf("Wrong size of staged files\nexpected: 1\ngot: %v", len(stageFiles))
Expand All @@ -37,3 +38,24 @@ func TestModifyAndStage(t *testing.T) {
t.Fatal("Object was not created for the staged file")
}
}

func TestAddRemovedFile(t *testing.T) {
testutils.ChDirToTemp(t)
commands.Init()

os.WriteFile("file_to_be_staged", []byte("content"), 0644)

commands.Add("file_to_be_staged")

commands.Commit("first")

os.Remove("file_to_be_staged")

commands.Add("file_to_be_staged")

manager := stage.Load()

if len(manager.AllObjects()) != 1 {
t.Fatal("wrong staged files size")
}
}
29 changes: 25 additions & 4 deletions cmd/commands/checkout.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,37 @@
package commands

import (
"fmt"
"mgit/cmd/structures/commit"
"mgit/cmd/structures/head"
"mgit/cmd/structures/tree"
"os"
)

func Checkout(ref string) {
func Checkout(ref string) error {
currentCommit := commit.GetCommitFromHead()

if currentCommit == nil {
return fmt.Errorf("%v invalid commit or not found", ref)
}

target := commit.FromHash(ref)

target.Tree.LoadBlobs()

for _, blob := range target.Tree.Blobs {
content := blob.ReadContent()
os.WriteFile(blob.FilePath, content, 0644)
diffs := currentCommit.Tree.Diff(*target.Tree)

for _, diff := range diffs {
switch diff.Type {
case tree.DiffDelete:
os.Remove(diff.TargetBlob.FilePath)
case tree.DiffModified, tree.DiffInsert, tree.DiffEqual:
content := diff.TargetBlob.ReadContent()
os.WriteFile(diff.TargetBlob.FilePath, content, 0644)
}
}

head.UpdateHead(target.Hash)

return nil
}
45 changes: 45 additions & 0 deletions cmd/commands/checkout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,48 @@ func TestTreeShouldInherit(t *testing.T) {
t.Fatal("one of the files was not reverted")
}
}

func TestWithDeletedFiles(t *testing.T) {
testutils.ChDirToTemp(t)

commands.Init()

os.WriteFile("file1", []byte{}, 0644)
os.WriteFile("file2", []byte{}, 0644)

commands.Add("file1", "file2")

hash1 := commands.Commit("first commit")

os.Remove("file2")

commands.Add("file2")

hash2 := commands.Commit("removed file2")

if hash2 == "" {
t.Fatal("no changes were detected when commiting, but a file was deleted")
}

commands.Checkout(hash1)

if _, err := os.Stat("file2"); os.IsNotExist(err) {
t.Fatal("Checkout should have restored file2")
}

commands.Checkout(hash2)
if _, err := os.Stat("file2"); err == nil {
t.Fatal("Checkout 2 should have deleted the \"file2\"")
}

}

func TestCheckoutNonExistentCommit(t *testing.T) {
testutils.ChDirToTemp(t)
commands.Init()

err := commands.Checkout("dumbasscommit")
if err == nil {
t.Fatal("expected error when checking out non-existent commit, got nil")
}
}
21 changes: 15 additions & 6 deletions cmd/commands/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@ package commands

import (
"fmt"
"mgit/cmd/storage"
"mgit/cmd/stage"
"mgit/cmd/structures/blob"
"mgit/cmd/structures/commit"
"mgit/cmd/structures/head"
"mgit/cmd/structures/tree"
"mgit/cmd/utils"
)

func Commit(message string) {
stages := storage.GetStages()
func Commit(message string) string {
stageManager := stage.Load()

if len(stages) == 0 {
if !stageManager.HasStages() {
fmt.Println("Nothing to commit")
return
return ""
}

stages := stageManager.Objects()

var parentHash string
var newTree *tree.Tree

Expand All @@ -31,13 +34,19 @@ func Commit(message string) {
parentHash = lastCommit.Hash
}

blobsToRemove := utils.Map(stageManager.DeletedObjects(), func(item stage.Object, key int) string {
return item.Path
})
newTree.RemoveBlobsByPath(blobsToRemove...)
newTree.Save()

newCommit := commit.CreateCommit(message, parentHash, newTree)
newCommit.Save()

storage.ClearStage()
stage.Truncate()
head.UpdateHead(newCommit.Hash)

fmt.Printf("Committed %v files\n\n", len(stages))

return newCommit.Hash
}
24 changes: 24 additions & 0 deletions cmd/commands/commit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,27 @@ func TestSimpleCommit(t *testing.T) {
t.Fatalf("wrong commit message\nexpected: commit message\ngot: %s", lastCommit.Message)
}
}

func TestCommitWithDeletedFile(t *testing.T) {
testutils.ChDirToTemp(t)

os.WriteFile("file", []byte("arquivo que precisa ser removido"), 0644)

commands.Init()
commands.Add("file")
h1 := commands.Commit("first")

commit.GetCommitFromHead()

os.Remove("file")

commands.Add("file")
h2 := commands.Commit("removed file")

c1 := commit.FromHash(h1)
c2 := commit.FromHash(h2)

if len(c1.Blobs()) != 1 || len(c2.Blobs()) != 0 {
t.Fatalf("Wrong commit blobs sizes\nc1: %v\n c2: %v\n", c1.Blobs(), c2.Blobs())
}
}
17 changes: 17 additions & 0 deletions cmd/commands/help.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package commands

import "fmt"

func PrintHelp() {
fmt.Print("available commands:\n\n")
fmt.Println("init\tCreate an empty MGit repository")
fmt.Println("add\tStage files to the storage.\n\tusage: mgit add file1 file2 file3")
fmt.Println("commit\tA commit is a reference in time of all the staged files. Create one.\n\tusage: mgit commit \"your commit message\"")
fmt.Println("log\tShow commit logs")
fmt.Println("checkout\tMove the head ref to a point in history")
fmt.Println("trackable\tShow the files that MGit can see and track")
fmt.Println("tracked\tShow files that has (at least) an older copy of itself in the current HEAD")
fmt.Println("untracked\tShow files that has no track in the current HEAD (files that are new to mgit)")
fmt.Println("rf\tShow files that have been removed and haven't been committed")
fmt.Println("cat-file\tGet uncompressed content of a file in the of the object storage")
}
12 changes: 12 additions & 0 deletions cmd/commands/removed_files.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package commands

import (
"fmt"
"mgit/cmd/structures/commit"
)

func RemovedFiles() {
for _, path := range commit.GetRemovedFiles() {
fmt.Println(path)
}
}
25 changes: 4 additions & 21 deletions cmd/commands/tracked.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,15 @@ package commands

import (
"fmt"
"log"
"mgit/cmd/structures/commit"
)

func Tracked() {
lastCommit := commit.GetCommitFromHead()
paths := commit.HeadTrackedFilesTree()

if lastCommit == nil {
fmt.Println("No commits were ever made")
return
for _, path := range paths {
fmt.Println(path)
}

tree := lastCommit.Tree

if tree == nil {
log.Fatal("no tree attached to the commit")
return
}

tree.LoadBlobs()

blobs := tree.Blobs

for _, blob := range blobs {
fmt.Println(blob.FilePath)
}

fmt.Printf("\nTotal of %v tracked files\n", len(blobs))
fmt.Printf("\nTotal of %v tracked files\n", len(paths))
}
55 changes: 55 additions & 0 deletions cmd/commands/untracked.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package commands

import (
"fmt"
"mgit/cmd/paths"
"mgit/cmd/structures/commit"
)

func trackedPaths() []string {
lastCommit := commit.GetCommitFromHead()

if lastCommit == nil {
return []string{}
}

tree := lastCommit.Tree

if tree == nil {
return []string{}
}

tree.LoadBlobs()
blobs := tree.Blobs
var paths []string = make([]string, len(blobs))

for i, blob := range blobs {
paths[i] = blob.FilePath
}

return paths
}

func Untracked() []string {
trackablePaths := paths.GetDirTree(".")
trackedPaths := trackedPaths()

var trackedMap map[string]bool = make(map[string]bool)

for _, path := range trackedPaths {
trackedMap[path] = false
}

var untrackedPaths []string = []string{}

for _, path := range trackablePaths {
if _, found := trackedMap[path]; found {
continue
}

untrackedPaths = append(untrackedPaths, path)
fmt.Println(path)
}

return untrackedPaths
}
Loading