github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/test/scripts/cmd/dependencies/github.go (about)

     1  package dependencies
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  
     7  	"github.com/0xPolygon/supernets2-node/log"
     8  	"github.com/go-git/go-billy/v5"
     9  	"github.com/go-git/go-billy/v5/helper/chroot"
    10  	"github.com/go-git/go-git/v5"
    11  	"github.com/go-git/go-git/v5/plumbing/transport"
    12  	"github.com/go-git/go-git/v5/plumbing/transport/http"
    13  	"github.com/go-git/go-git/v5/plumbing/transport/ssh"
    14  	"github.com/go-git/go-git/v5/storage/memory"
    15  	"github.com/spf13/afero"
    16  )
    17  
    18  type githubManager struct {
    19  	aferoFs afero.Fs
    20  
    21  	sshKey string
    22  	token  string
    23  }
    24  
    25  func newGithubManager(aferoFs afero.Fs, sshKey, token string) *githubManager {
    26  	return &githubManager{
    27  		aferoFs: aferoFs,
    28  		token:   token,
    29  		sshKey:  sshKey,
    30  	}
    31  }
    32  
    33  func (gm *githubManager) cloneTargetRepo(repoURL string) (string, error) {
    34  	tmpdir, err := afero.TempDir(gm.aferoFs, "", "supernets2-node-deps")
    35  	if err != nil {
    36  		return "", err
    37  	}
    38  	billyFS := newAdapter(gm.aferoFs)
    39  	billyFS, err = billyFS.Chroot(tmpdir)
    40  	if err != nil {
    41  		return "", err
    42  	}
    43  	cloneOptions := &git.CloneOptions{
    44  		URL: repoURL,
    45  	}
    46  	if gm.token != "" || gm.sshKey != "" {
    47  		auth, err := gm.determineAuth()
    48  		if err != nil {
    49  			return "", err
    50  		}
    51  		if auth != nil {
    52  			cloneOptions.Auth = auth
    53  		}
    54  	}
    55  	storer := memory.NewStorage()
    56  	_, err = git.Clone(storer, billyFS, cloneOptions)
    57  	if err != nil {
    58  		return "", err
    59  	}
    60  	return tmpdir, nil
    61  }
    62  
    63  func (gm *githubManager) determineAuth() (transport.AuthMethod, error) {
    64  	if gm.token != "" {
    65  		return &http.BasicAuth{
    66  			Username: "int-bot", // this can be anything except an empty string
    67  			Password: gm.token,
    68  		}, nil
    69  	}
    70  
    71  	pvkFile, err := afero.TempFile(gm.aferoFs, "", "")
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	defer func() {
    76  		if err := gm.aferoFs.Remove(pvkFile.Name()); err != nil {
    77  			log.Errorf("Could not remove temporary file %q: %v", pvkFile.Name(), err)
    78  		}
    79  	}()
    80  	_, err = pvkFile.WriteString(gm.sshKey + "\n")
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	const defaultUser = "git"
    85  	auth, err := ssh.NewPublicKeysFromFile(defaultUser, pvkFile.Name(), "")
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	return auth, nil
    91  }
    92  
    93  const (
    94  	defaultDirectoryMode = 0755
    95  	defaultCreateMode    = 0666
    96  )
    97  
    98  // AdapterFs holds an afero Fs interface for adaptation to billy.Filesystem.
    99  type AdapterFs struct {
   100  	fs afero.Fs
   101  }
   102  
   103  func newAdapter(fs afero.Fs) billy.Filesystem {
   104  	return chroot.New(&AdapterFs{fs}, "/")
   105  }
   106  
   107  // Create creates a new file.
   108  func (fs *AdapterFs) Create(filename string) (billy.File, error) {
   109  	return fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, defaultCreateMode)
   110  }
   111  
   112  // OpenFile opens a file.
   113  func (fs *AdapterFs) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) {
   114  	if flag&os.O_CREATE != 0 {
   115  		if err := fs.createDir(filename); err != nil {
   116  			return nil, err
   117  		}
   118  	}
   119  
   120  	f, err := fs.fs.OpenFile(filename, flag, perm)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	mutexFile := &file{
   126  		File: f,
   127  	}
   128  
   129  	return mutexFile, err
   130  }
   131  
   132  func (fs *AdapterFs) createDir(fullpath string) error {
   133  	dir := filepath.Dir(fullpath)
   134  	if dir != "." {
   135  		if err := fs.fs.MkdirAll(dir, defaultDirectoryMode); err != nil {
   136  			return err
   137  		}
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  // ReadDir reads a directory.
   144  func (fs *AdapterFs) ReadDir(path string) ([]os.FileInfo, error) {
   145  	l, err := afero.ReadDir(fs.fs, path)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	var s = make([]os.FileInfo, len(l))
   151  	copy(s, l)
   152  
   153  	return s, nil
   154  }
   155  
   156  // Rename renames the given file.
   157  func (fs *AdapterFs) Rename(from, to string) error {
   158  	if err := fs.createDir(to); err != nil {
   159  		return err
   160  	}
   161  
   162  	return os.Rename(from, to)
   163  }
   164  
   165  // MkdirAll creates directories recursively.
   166  func (fs *AdapterFs) MkdirAll(path string, perm os.FileMode) error {
   167  	return fs.fs.MkdirAll(path, defaultDirectoryMode)
   168  }
   169  
   170  // Open opens a file.
   171  func (fs *AdapterFs) Open(filename string) (billy.File, error) {
   172  	return fs.OpenFile(filename, os.O_RDONLY, 0)
   173  }
   174  
   175  // Stat returns information about a file.
   176  func (fs *AdapterFs) Stat(filename string) (os.FileInfo, error) {
   177  	return fs.fs.Stat(filename)
   178  }
   179  
   180  // Remove deletes a file.
   181  func (fs *AdapterFs) Remove(filename string) error {
   182  	return fs.fs.Remove(filename)
   183  }
   184  
   185  // TempFile creates a temporary file.
   186  func (fs *AdapterFs) TempFile(dir, prefix string) (billy.File, error) {
   187  	if err := fs.createDir(dir + string(os.PathSeparator)); err != nil {
   188  		return nil, err
   189  	}
   190  
   191  	f, err := afero.TempFile(fs.fs, dir, prefix)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  	return &file{File: f}, nil
   196  }
   197  
   198  // Join returns a string with joined paths.
   199  func (fs *AdapterFs) Join(elem ...string) string {
   200  	return filepath.Join(elem...)
   201  }
   202  
   203  // RemoveAll removes directories recursively.
   204  func (fs *AdapterFs) RemoveAll(path string) error {
   205  	return fs.fs.RemoveAll(filepath.Clean(path))
   206  }
   207  
   208  // Lstat returns information about a file.
   209  func (fs *AdapterFs) Lstat(filename string) (os.FileInfo, error) {
   210  	info, success := fs.fs.(afero.Lstater)
   211  	if success {
   212  		s, _, err := info.LstatIfPossible(filename)
   213  		if err != nil {
   214  			return nil, err
   215  		}
   216  
   217  		return s, nil
   218  	}
   219  
   220  	return fs.fs.Stat(filename)
   221  }
   222  
   223  // Symlink creates a symbolic link.
   224  func (fs *AdapterFs) Symlink(target, link string) error {
   225  	if err := fs.createDir(link); err != nil {
   226  		return err
   227  	}
   228  
   229  	// TODO afero does not support symlinks
   230  	return nil
   231  }
   232  
   233  // Readlink is not currently implemented.
   234  func (fs *AdapterFs) Readlink(link string) (string, error) {
   235  	// TODO afero does not support symlinks
   236  	return "", nil
   237  }
   238  
   239  // Capabilities implements the Capable interface.
   240  func (fs *AdapterFs) Capabilities() billy.Capability {
   241  	return billy.DefaultCapabilities
   242  }
   243  
   244  // file is a wrapper for an os.File which adds support for file locking.
   245  type file struct {
   246  	afero.File
   247  }
   248  
   249  // Lock is not currently implemented.
   250  func (f *file) Lock() error {
   251  	return nil
   252  }
   253  
   254  // Unlock is not currently implemented.
   255  func (f *file) Unlock() error {
   256  	return nil
   257  }