@@ -2,13 +2,16 @@ package main
22
33import (
44 "errors"
5+ "fmt"
56 "io"
67 "io/ioutil"
78 "log"
89 "os"
10+ "os/exec"
911 "path/filepath"
1012 "strings"
1113 "sync"
14+ "unicode"
1215
1316 "github.com/go-sharp/color"
1417)
@@ -19,6 +22,120 @@ type publishCmd struct {
1922 } `positional-args:"yes" required:"1"`
2023}
2124
25+ type JFrogPublishCmd struct {
26+ publishCmd
27+ JFrogBinPath string `long:"jfrog-bin" env:"GOP_JFROG_BIN" description:"Set full path to the jfrog-cli binary"`
28+ Repo string `short:"r" long:"repo" required:"yes" description:"Artifactory go repository name ex. go-local."`
29+ }
30+
31+ // Execute will be called for the last active (sub)command. The
32+ // args argument contains the remaining command line arguments. The
33+ // error that Execute returns will be eventually passed out of the
34+ // Parse method of the Parser.
35+ func (j * JFrogPublishCmd ) Execute (args []string ) error {
36+ log .SetPrefix ("Publish-JFrog: " )
37+ if j .JFrogBinPath == "" {
38+ if p , err := exec .LookPath ("jfrog" ); err == nil {
39+ if ! filepath .IsAbs (p ) {
40+ p , _ = filepath .Abs (p )
41+ }
42+ j .JFrogBinPath = p
43+ }
44+ }
45+
46+ if j .JFrogBinPath == "" {
47+ log .Fatalln (errorRedPrefix , "missing jfrog cli: install jfrog-cli or specify valid binary path with --jfrog-bin" )
48+ }
49+
50+ cfg := j .getJFrogCfg ()
51+ if len (cfg ) == 0 {
52+ log .Fatalln (errorRedPrefix , "jfrog is not configured" )
53+ }
54+
55+ // Print config used
56+ for _ , i := range cfg {
57+ log .Println ("config:" , color .BlueString (i ))
58+ }
59+
60+ workDir , cleanFn := createTempWorkDir ()
61+ defer cleanFn ()
62+
63+ log .Println ("extracting archive" )
64+ if err := extractZipArchive (j .PosArgs .Archive , workDir ); err != nil {
65+ log .Fatalln (errorRedPrefix , " failed to extract archive:" , err )
66+ }
67+
68+ workCh := make (chan string , 10 )
69+ doneCh := make (chan struct {})
70+ go func () {
71+ for mod := range workCh {
72+ pkg := strings .Split (filepath .Base (mod ), "@" )
73+ if len (pkg ) != 2 {
74+ log .Println (color .YellowString ("warning:" ), "invalid module directory:" , filepath .Base (mod ))
75+ continue
76+ }
77+
78+ goModF := filepath .Join (mod , "go.mod" )
79+ if _ , err := os .Stat (goModF ); errors .Is (err , os .ErrNotExist ) {
80+ modName := filepath .Dir (strings .TrimPrefix (mod , workDir + string (filepath .Separator )))
81+ modName = strToModuleName (modName + "/" + pkg [0 ])
82+ if err := ioutil .WriteFile (goModF , []byte (fmt .Sprintf ("module %v\n " , modName )), 0664 ); err != nil {
83+ verboseF ("%v: %v\n " , errorRedPrefix , err )
84+ }
85+ }
86+
87+ cmd := exec .Command (j .JFrogBinPath , "rt" , "gp" , j .Repo , pkg [1 ])
88+ cmd .Dir = mod
89+
90+ verboseF ("publishing module %v %v\n " , color .BlueString (pkg [0 ]), color .BlueString (pkg [1 ]))
91+ if output , err := cmd .CombinedOutput (); err != nil {
92+ log .Println (errorRedPrefix , "failed publish module:" , pkg [0 ], pkg [1 ], err )
93+ if len (output ) > 0 {
94+ verboseF ("%v\n %v" , errorRedPrefix , string (output ))
95+ }
96+ continue
97+ }
98+ }
99+ doneCh <- struct {}{}
100+ }()
101+
102+ log .Println ("publishing modules" )
103+ filepath .Walk (workDir , func (path string , info os.FileInfo , err error ) error {
104+ if strings .HasPrefix (info .Name (), "cache" ) {
105+ return filepath .SkipDir
106+ }
107+
108+ if ! info .IsDir () || ! strings .Contains (info .Name (), "@" ) {
109+ return nil
110+ }
111+ workCh <- path
112+ return filepath .SkipDir
113+ })
114+ close (workCh )
115+
116+ <- doneCh
117+
118+ log .Println ("modules successfully uploaded" )
119+ return nil
120+ }
121+
122+ func (j JFrogPublishCmd ) getJFrogCfg () (config []string ) {
123+ data , err := exec .Command (j .JFrogBinPath , "rt" , "c" , "show" ).Output ()
124+ if err != nil {
125+ log .Fatalln (errorRedPrefix , "failed to get jfrog config:" , err )
126+ }
127+
128+ for _ , v := range strings .Split (string (data ), "\n " ) {
129+ if strings .HasPrefix (strings .ToLower (v ), "server" ) || strings .HasPrefix (strings .ToLower (v ), "url" ) ||
130+ strings .HasPrefix (strings .ToLower (v ), "user" ) {
131+ config = append (config , v )
132+ }
133+ }
134+
135+ return config
136+ }
137+
138+ // FolderPublishCmd publishes an archive of modules to a folder.
22139type FolderPublishCmd struct {
23140 publishCmd
24141 Output string `short:"o" long:"out" required:"yes" description:"Output folder for the archive."`
@@ -182,3 +299,25 @@ func (f FolderPublishCmd) handleCopyFile(path, relPath string) {
182299 return
183300 }
184301}
302+
303+ func strToModuleName (name string ) string {
304+ name = filepath .ToSlash (name )
305+ var modName []rune
306+
307+ nextToUpper := false
308+ for _ , v := range name {
309+ if nextToUpper {
310+ modName = append (modName , unicode .ToUpper (v ))
311+ nextToUpper = false
312+ continue
313+ }
314+
315+ if v == '!' {
316+ nextToUpper = true
317+ continue
318+ }
319+ modName = append (modName , v )
320+ }
321+
322+ return string (modName )
323+ }
0 commit comments