66 "io"
77 "os"
88
9+ "gopkg.in/src-d/go-billy.v4/util"
910 "gopkg.in/src-d/go-git.v4/plumbing"
1011 "gopkg.in/src-d/go-git.v4/plumbing/filemode"
1112 "gopkg.in/src-d/go-git.v4/plumbing/format/gitignore"
@@ -18,9 +19,16 @@ import (
1819 "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder"
1920)
2021
21- // ErrDestinationExists in an Move operation means that the target exists on
22- // the worktree.
23- var ErrDestinationExists = errors .New ("destination exists" )
22+ var (
23+ // ErrDestinationExists in an Move operation means that the target exists on
24+ // the worktree.
25+ ErrDestinationExists = errors .New ("destination exists" )
26+ // ErrGlobNoMatches in an AddGlob if the glob pattern does not match any
27+ // file in the worktree.ErrNotDirectory
28+ ErrGlobNoMatches = errors .New ("glob pattern did not match any files" )
29+ // ErrNotDirectory in an AddDirectory if the path is not a directory.
30+ ErrNotDirectory = errors .New ("path is not a directory" )
31+ )
2432
2533// Status returns the working tree status.
2634func (w * Worktree ) Status () (Status , error ) {
@@ -243,30 +251,170 @@ func diffTreeIsEquals(a, b noder.Hasher) bool {
243251}
244252
245253// Add adds the file contents of a file in the worktree to the index. if the
246- // file is already staged in the index no error is returned.
254+ // file is already staged in the index no error is returned. If a file deleted
255+ // from the Workspace is given, the file is removed from the index.
247256func (w * Worktree ) Add (path string ) (plumbing.Hash , error ) {
248257 s , err := w .Status ()
249258 if err != nil {
250259 return plumbing .ZeroHash , err
251260 }
252261
253- h , err := w .copyFileToStorage (path )
262+ idx , err := w .r .Storer .Index ()
263+ if err != nil {
264+ return plumbing .ZeroHash , err
265+ }
266+
267+ added , h , err := w .doAdd (idx , s , path )
268+ if err != nil {
269+ return h , err
270+ }
271+
272+ if ! added {
273+ return h , nil
274+ }
275+
276+ return h , w .r .Storer .SetIndex (idx )
277+ }
278+
279+ // AddDirectory adds the files contents of a directory and all his
280+ // sub-directories recursively in the worktree to the index. If any of the
281+ // file is already staged in the index no error is returned.
282+ func (w * Worktree ) AddDirectory (path string ) error {
283+ fi , err := w .Filesystem .Lstat (path )
284+ if err != nil {
285+ return err
286+ }
287+
288+ if ! fi .IsDir () {
289+ return ErrNotDirectory
290+ }
291+
292+ s , err := w .Status ()
293+ if err != nil {
294+ return err
295+ }
296+
297+ idx , err := w .r .Storer .Index ()
298+ if err != nil {
299+ return err
300+ }
301+
302+ added , err := w .doAddDirectory (idx , s , path )
303+ if err != nil {
304+ return err
305+ }
306+
307+ if ! added {
308+ return nil
309+ }
310+
311+ return w .r .Storer .SetIndex (idx )
312+ }
313+
314+ func (w * Worktree ) doAddDirectory (idx * index.Index , s Status , path string ) (added bool , err error ) {
315+ files , err := w .Filesystem .ReadDir (path )
316+ if err != nil {
317+ return false , err
318+ }
319+
320+ for _ , file := range files {
321+ name := w .Filesystem .Join (path , file .Name ())
322+
323+ var a bool
324+ if file .IsDir () {
325+ a , err = w .doAddDirectory (idx , s , name )
326+ } else {
327+ a , _ , err = w .doAdd (idx , s , name )
328+ }
329+
330+ if err != nil {
331+ return
332+ }
333+
334+ if ! added && a {
335+ added = true
336+ }
337+ }
338+
339+ return
340+
341+ }
342+
343+ // AddGlob given a glob pattern adds all the matching files content and all his
344+ // sub-directories recursively in the worktree to the index. If any of the
345+ // file is already staged in the index no error is returned.
346+ func (w * Worktree ) AddGlob (pattern string ) error {
347+ files , err := util .Glob (w .Filesystem , pattern )
348+ if err != nil {
349+ return err
350+ }
351+
352+ if len (files ) == 0 {
353+ return ErrGlobNoMatches
354+ }
355+
356+ s , err := w .Status ()
357+ if err != nil {
358+ return err
359+ }
360+
361+ idx , err := w .r .Storer .Index ()
362+ if err != nil {
363+ return err
364+ }
365+
366+ var saveIndex bool
367+ for _ , file := range files {
368+ fi , err := w .Filesystem .Lstat (file )
369+ if err != nil {
370+ return err
371+ }
372+
373+ var added bool
374+ if fi .IsDir () {
375+ added , err = w .doAddDirectory (idx , s , file )
376+ } else {
377+ added , _ , err = w .doAdd (idx , s , file )
378+ }
379+
380+ if err != nil {
381+ return err
382+ }
383+
384+ if ! saveIndex && added {
385+ saveIndex = true
386+ }
387+ }
388+
389+ if saveIndex {
390+ return w .r .Storer .SetIndex (idx )
391+ }
392+
393+ return nil
394+ }
395+
396+ // doAdd create a new blob from path and update the index, added is true if
397+ // the file added is different from the index.
398+ func (w * Worktree ) doAdd (idx * index.Index , s Status , path string ) (added bool , h plumbing.Hash , err error ) {
399+ h , err = w .copyFileToStorage (path )
254400 if err != nil {
255401 if os .IsNotExist (err ) {
256- h , err = w .deleteFromIndex (path )
402+ added = true
403+ h , err = w .deleteFromIndex (idx , path )
257404 }
258- return h , err
405+
406+ return
259407 }
260408
261409 if s .File (path ).Worktree == Unmodified {
262- return h , nil
410+ return false , h , nil
263411 }
264412
265- if err := w .addOrUpdateFileToIndex (path , h ); err != nil {
266- return h , err
413+ if err := w .addOrUpdateFileToIndex (idx , path , h ); err != nil {
414+ return false , h , err
267415 }
268416
269- return h , err
417+ return true , h , err
270418}
271419
272420func (w * Worktree ) copyFileToStorage (path string ) (hash plumbing.Hash , err error ) {
@@ -324,28 +472,17 @@ func (w *Worktree) fillEncodedObjectFromSymlink(dst io.Writer, path string, fi o
324472 return err
325473}
326474
327- func (w * Worktree ) addOrUpdateFileToIndex (filename string , h plumbing.Hash ) error {
328- idx , err := w .r .Storer .Index ()
329- if err != nil {
330- return err
331- }
332-
475+ func (w * Worktree ) addOrUpdateFileToIndex (idx * index.Index , filename string , h plumbing.Hash ) error {
333476 e , err := idx .Entry (filename )
334477 if err != nil && err != index .ErrEntryNotFound {
335478 return err
336479 }
337480
338481 if err == index .ErrEntryNotFound {
339- if err := w .doAddFileToIndex (idx , filename , h ); err != nil {
340- return err
341- }
342- } else {
343- if err := w .doUpdateFileToIndex (e , filename , h ); err != nil {
344- return err
345- }
482+ return w .doAddFileToIndex (idx , filename , h )
346483 }
347484
348- return w .r . Storer . SetIndex ( idx )
485+ return w .doUpdateFileToIndex ( e , filename , h )
349486}
350487
351488func (w * Worktree ) doAddFileToIndex (idx * index.Index , filename string , h plumbing.Hash ) error {
@@ -378,26 +515,30 @@ func (w *Worktree) doUpdateFileToIndex(e *index.Entry, filename string, h plumbi
378515
379516// Remove removes files from the working tree and from the index.
380517func (w * Worktree ) Remove (path string ) (plumbing.Hash , error ) {
381- hash , err := w .deleteFromIndex ( path )
518+ idx , err := w .r . Storer . Index ( )
382519 if err != nil {
383520 return plumbing .ZeroHash , err
384521 }
385522
386- return hash , w .deleteFromFilesystem (path )
387- }
388-
389- func (w * Worktree ) deleteFromIndex (path string ) (plumbing.Hash , error ) {
390- idx , err := w .r .Storer .Index ()
523+ hash , err := w .deleteFromIndex (idx , path )
391524 if err != nil {
392525 return plumbing .ZeroHash , err
393526 }
394527
528+ if err := w .deleteFromFilesystem (path ); err != nil {
529+ return hash , err
530+ }
531+
532+ return hash , w .r .Storer .SetIndex (idx )
533+ }
534+
535+ func (w * Worktree ) deleteFromIndex (idx * index.Index , path string ) (plumbing.Hash , error ) {
395536 e , err := idx .Remove (path )
396537 if err != nil {
397538 return plumbing .ZeroHash , err
398539 }
399540
400- return e .Hash , w . r . Storer . SetIndex ( idx )
541+ return e .Hash , nil
401542}
402543
403544func (w * Worktree ) deleteFromFilesystem (path string ) error {
@@ -420,7 +561,12 @@ func (w *Worktree) Move(from, to string) (plumbing.Hash, error) {
420561 return plumbing .ZeroHash , ErrDestinationExists
421562 }
422563
423- hash , err := w .deleteFromIndex (from )
564+ idx , err := w .r .Storer .Index ()
565+ if err != nil {
566+ return plumbing .ZeroHash , err
567+ }
568+
569+ hash , err := w .deleteFromIndex (idx , from )
424570 if err != nil {
425571 return plumbing .ZeroHash , err
426572 }
@@ -429,5 +575,9 @@ func (w *Worktree) Move(from, to string) (plumbing.Hash, error) {
429575 return hash , err
430576 }
431577
432- return hash , w .addOrUpdateFileToIndex (to , hash )
578+ if err := w .addOrUpdateFileToIndex (idx , to , hash ); err != nil {
579+ return hash , err
580+ }
581+
582+ return hash , w .r .Storer .SetIndex (idx )
433583}
0 commit comments