@@ -6,10 +6,14 @@ import (
6
6
"fmt"
7
7
"io/ioutil"
8
8
"os"
9
+ "os/exec"
9
10
"path/filepath"
11
+ "runtime"
10
12
"sort"
11
13
"strings"
12
14
15
+ "gopkg.in/src-d/go-git.v4"
16
+
13
17
"github.com/vim-volt/volt/config"
14
18
"github.com/vim-volt/volt/fileutil"
15
19
"github.com/vim-volt/volt/gitutil"
@@ -20,7 +24,6 @@ import (
20
24
"github.com/vim-volt/volt/transaction"
21
25
22
26
multierror "github.com/hashicorp/go-multierror"
23
- "gopkg.in/src-d/go-git.v4"
24
27
)
25
28
26
29
func init () {
@@ -211,7 +214,7 @@ func (cmd *getCmd) doGet(reposPathList []pathutil.ReposPath, lockJSON *lockjson.
211
214
repos = nil
212
215
}
213
216
if repos == nil || repos .Type == lockjson .ReposGitType {
214
- go cmd .getParallel (reposPath , repos , * cfg . Get . CreateSkeletonPlugconf , done )
217
+ go cmd .getParallel (reposPath , repos , cfg , done )
215
218
getCount ++
216
219
}
217
220
}
@@ -310,11 +313,11 @@ const (
310
313
// This function is executed in goroutine of each plugin.
311
314
// 1. install plugin if it does not exist
312
315
// 2. install plugconf if it does not exist and createPlugconf=true
313
- func (cmd * getCmd ) getParallel (reposPath pathutil.ReposPath , repos * lockjson.Repos , createPlugconf bool , done chan <- getParallelResult ) {
316
+ func (cmd * getCmd ) getParallel (reposPath pathutil.ReposPath , repos * lockjson.Repos , cfg * config. Config , done chan <- getParallelResult ) {
314
317
pluginDone := make (chan getParallelResult )
315
- go cmd .installPlugin (reposPath , repos , pluginDone )
318
+ go cmd .installPlugin (reposPath , repos , cfg , pluginDone )
316
319
pluginResult := <- pluginDone
317
- if pluginResult .err != nil || ! createPlugconf {
320
+ if pluginResult .err != nil || ! * cfg . Get . CreateSkeletonPlugconf {
318
321
done <- pluginResult
319
322
return
320
323
}
@@ -323,7 +326,7 @@ func (cmd *getCmd) getParallel(reposPath pathutil.ReposPath, repos *lockjson.Rep
323
326
done <- (<- plugconfDone )
324
327
}
325
328
326
- func (cmd * getCmd ) installPlugin (reposPath pathutil.ReposPath , repos * lockjson.Repos , done chan <- getParallelResult ) {
329
+ func (cmd * getCmd ) installPlugin (reposPath pathutil.ReposPath , repos * lockjson.Repos , cfg * config. Config , done chan <- getParallelResult ) {
327
330
// true:upgrade, false:install
328
331
fullReposPath := pathutil .FullReposPath (reposPath )
329
332
doUpgrade := cmd .upgrade && pathutil .Exists (fullReposPath )
@@ -366,7 +369,7 @@ func (cmd *getCmd) installPlugin(reposPath pathutil.ReposPath, repos *lockjson.R
366
369
}
367
370
// Upgrade plugin
368
371
logger .Debug ("Upgrading " + reposPath + " ..." )
369
- err := cmd .upgradePlugin (reposPath )
372
+ err := cmd .upgradePlugin (reposPath , cfg )
370
373
if err != git .NoErrAlreadyUpToDate && err != nil {
371
374
result := errors .New ("failed to upgrade plugin: " + err .Error ())
372
375
logger .Debug ("Rollbacking " + fullReposPath + " ..." )
@@ -389,7 +392,7 @@ func (cmd *getCmd) installPlugin(reposPath pathutil.ReposPath, repos *lockjson.R
389
392
} else if doInstall {
390
393
// Install plugin
391
394
logger .Debug ("Installing " + reposPath + " ..." )
392
- err := cmd .clonePlugin (reposPath )
395
+ err := cmd .clonePlugin (reposPath , cfg )
393
396
if err != nil {
394
397
result := errors .New ("failed to install plugin: " + err .Error ())
395
398
logger .Debug ("Rollbacking " + fullReposPath + " ..." )
@@ -495,15 +498,15 @@ func (*getCmd) rollbackRepos(fullReposPath string) error {
495
498
return nil
496
499
}
497
500
498
- func (cmd * getCmd ) upgradePlugin (reposPath pathutil.ReposPath ) error {
501
+ func (cmd * getCmd ) upgradePlugin (reposPath pathutil.ReposPath , cfg * config. Config ) error {
499
502
fullpath := pathutil .FullReposPath (reposPath )
500
503
501
504
repos , err := git .PlainOpen (fullpath )
502
505
if err != nil {
503
506
return err
504
507
}
505
508
506
- cfg , err := repos .Config ()
509
+ reposCfg , err := repos .Config ()
507
510
if err != nil {
508
511
return err
509
512
}
@@ -513,25 +516,16 @@ func (cmd *getCmd) upgradePlugin(reposPath pathutil.ReposPath) error {
513
516
return err
514
517
}
515
518
516
- if cfg .Core .IsBare {
517
- return repos .Fetch (& git.FetchOptions {
518
- RemoteName : remote ,
519
- })
519
+ if reposCfg .Core .IsBare {
520
+ return cmd .gitFetch (repos , fullpath , remote , cfg )
520
521
} else {
521
- wt , err := repos .Worktree ()
522
- if err != nil {
523
- return err
524
- }
525
- return wt .Pull (& git.PullOptions {
526
- RemoteName : remote ,
527
- RecurseSubmodules : 10 ,
528
- })
522
+ return cmd .gitPull (repos , fullpath , remote , cfg )
529
523
}
530
524
}
531
525
532
526
var errRepoExists = errors .New ("repository exists" )
533
527
534
- func (cmd * getCmd ) clonePlugin (reposPath pathutil.ReposPath ) error {
528
+ func (cmd * getCmd ) clonePlugin (reposPath pathutil.ReposPath , cfg * config. Config ) error {
535
529
fullpath := pathutil .FullReposPath (reposPath )
536
530
if pathutil .Exists (fullpath ) {
537
531
return errRepoExists
@@ -543,16 +537,7 @@ func (cmd *getCmd) clonePlugin(reposPath pathutil.ReposPath) error {
543
537
}
544
538
545
539
// Clone repository to $VOLTPATH/repos/{site}/{user}/{name}
546
- isBare := false
547
- r , err := git .PlainClone (fullpath , isBare , & git.CloneOptions {
548
- URL : pathutil .CloneURL (reposPath ),
549
- RecurseSubmodules : 10 ,
550
- })
551
- if err != nil {
552
- return err
553
- }
554
-
555
- return gitutil .SetUpstreamRemote (r , "origin" )
540
+ return cmd .gitClone (pathutil .CloneURL (reposPath ), fullpath , cfg )
556
541
}
557
542
558
543
func (cmd * getCmd ) fetchPlugconf (reposPath pathutil.ReposPath ) error {
@@ -616,3 +601,111 @@ func (*getCmd) updateReposVersion(lockJSON *lockjson.LockJSON, reposPath pathuti
616
601
}
617
602
return added
618
603
}
604
+
605
+ func (cmd * getCmd ) gitFetch (r * git.Repository , workDir string , remote string , cfg * config.Config ) error {
606
+ err := r .Fetch (& git.FetchOptions {
607
+ RemoteName : remote ,
608
+ })
609
+ if err == nil || err == git .NoErrAlreadyUpToDate {
610
+ return err
611
+ }
612
+
613
+ // When fallback_git_cmd is true and git command is installed,
614
+ // try to invoke git-fetch command
615
+ if ! * cfg .Get .FallbackGitCmd || ! cmd .hasGitCmd () {
616
+ return err
617
+ }
618
+ logger .Warnf ("failed to fetch, try to execute \" git fetch %s\" instead...: %s" , remote , err .Error ())
619
+
620
+ before , err := gitutil .GetHEADRepository (r )
621
+ fetch := exec .Command ("git" , "fetch" , remote )
622
+ fetch .Dir = workDir
623
+ err = fetch .Run ()
624
+ if err != nil {
625
+ return err
626
+ }
627
+ if changed , err := cmd .getWorktreeChanges (r , before ); err != nil {
628
+ return err
629
+ } else if ! changed {
630
+ return git .NoErrAlreadyUpToDate
631
+ }
632
+ return nil
633
+ }
634
+
635
+ func (cmd * getCmd ) gitPull (r * git.Repository , workDir string , remote string , cfg * config.Config ) error {
636
+ wt , err := r .Worktree ()
637
+ if err != nil {
638
+ return err
639
+ }
640
+ err = wt .Pull (& git.PullOptions {
641
+ RemoteName : remote ,
642
+ RecurseSubmodules : 10 ,
643
+ })
644
+ if err == nil || err == git .NoErrAlreadyUpToDate {
645
+ return err
646
+ }
647
+
648
+ // When fallback_git_cmd is true and git command is installed,
649
+ // try to invoke git-pull command
650
+ if ! * cfg .Get .FallbackGitCmd || ! cmd .hasGitCmd () {
651
+ return err
652
+ }
653
+ logger .Warnf ("failed to pull, try to execute \" git pull\" instead...: %s" , err .Error ())
654
+
655
+ before , err := gitutil .GetHEADRepository (r )
656
+ pull := exec .Command ("git" , "pull" )
657
+ pull .Dir = workDir
658
+ err = pull .Run ()
659
+ if err != nil {
660
+ return err
661
+ }
662
+ if changed , err := cmd .getWorktreeChanges (r , before ); err != nil {
663
+ return err
664
+ } else if ! changed {
665
+ return git .NoErrAlreadyUpToDate
666
+ }
667
+ return nil
668
+ }
669
+
670
+ func (cmd * getCmd ) getWorktreeChanges (r * git.Repository , before string ) (bool , error ) {
671
+ after , err := gitutil .GetHEADRepository (r )
672
+ if err != nil {
673
+ return false , err
674
+ }
675
+ return before != after , nil
676
+ }
677
+
678
+ func (cmd * getCmd ) gitClone (cloneURL , dstDir string , cfg * config.Config ) error {
679
+ isBare := false
680
+ r , err := git .PlainClone (dstDir , isBare , & git.CloneOptions {
681
+ URL : cloneURL ,
682
+ RecurseSubmodules : 10 ,
683
+ })
684
+ if err != nil {
685
+ // When fallback_git_cmd is true and git command is installed,
686
+ // try to invoke git-clone command
687
+ if ! * cfg .Get .FallbackGitCmd || ! cmd .hasGitCmd () {
688
+ return err
689
+ }
690
+ logger .Warnf ("failed to clone, try to execute \" git clone --recursive %s %s\" instead...: %s" , cloneURL , dstDir , err .Error ())
691
+ err = os .RemoveAll (dstDir )
692
+ if err != nil {
693
+ return err
694
+ }
695
+ out , err := exec .Command ("git" , "clone" , "--recursive" , cloneURL , dstDir ).CombinedOutput ()
696
+ if err != nil {
697
+ return fmt .Errorf ("\" git clone --recursive %s %s\" failed, out=%s: %s" , cloneURL , dstDir , string (out ), err .Error ())
698
+ }
699
+ }
700
+
701
+ return gitutil .SetUpstreamRemote (r , "origin" )
702
+ }
703
+
704
+ func (cmd * getCmd ) hasGitCmd () bool {
705
+ exeName := "git"
706
+ if runtime .GOOS == "windows" {
707
+ exeName = "git.exe"
708
+ }
709
+ _ , err := exec .LookPath (exeName )
710
+ return err == nil
711
+ }
0 commit comments