-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[nexus-cli] upload jar into repository
- command line - docker to run
- Loading branch information
0 parents
commit cbf1b89
Showing
6 changed files
with
596 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
FROM golang:1.9 | ||
|
||
WORKDIR /go/src/github.com/sjeandeaux/nexus-cli | ||
COPY . . | ||
|
||
RUN go-wrapper download # "go get -d -v ./..." | ||
RUN go-wrapper install # "go install -v ./..." | ||
|
||
ENTRYPOINT ["go-wrapper" , "run"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# nexus-cli | ||
|
||
## upload | ||
|
||
I share a volume where i have my upload.jar file. | ||
|
||
```bash | ||
|
||
#run your own nexus | ||
docker run -d -P --name nexus sonatype/nexus3:3.5.1 | ||
docker build --tag sjeandeaux/nexus-cli . | ||
docker run --link nexus:nexus -ti -v $(pwd):$(pwd):ro sjeandeaux/nexus-cli \ | ||
-repo=http://nexus:8081/repository/maven-releases \ | ||
-user=admin \ | ||
-password=admin123 \ | ||
-file=$(pwd)/upload.jar \ | ||
-groupID=com.jeandeaux \ | ||
-artifactID=elyne \ | ||
-version=0.1.0 \ | ||
-hash md5 \ | ||
-hash sha1 | ||
|
||
``` | ||
|
||
## TODOs | ||
|
||
- [ ] interface for artifact | ||
- [ ] interface for repository | ||
- [ ] integration tests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package log | ||
|
||
import ( | ||
"io/ioutil" | ||
"log" | ||
) | ||
|
||
// Logger logger of application. | ||
var Logger *log.Logger = log.New(ioutil.Discard, "[☯ nexus-cli ☯] ⇒ ", log.Ldate|log.Ltime|log.LUTC) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
|
||
"fmt" | ||
|
||
"github.com/sjeandeaux/nexus-cli/log" | ||
"github.com/sjeandeaux/nexus-cli/repositorymanager" | ||
|
||
"os" | ||
) | ||
|
||
type enableHash []string | ||
|
||
func (i *enableHash) String() string { | ||
return fmt.Sprintf("%s", *i) | ||
} | ||
|
||
func (i *enableHash) Set(value string) error { | ||
*i = append(*i, value) | ||
return nil | ||
} | ||
|
||
//commandLineArgs all parameters in command line | ||
type commandLineArgs struct { | ||
//url of repository to upload file | ||
urlOfRepository string | ||
user string | ||
password string | ||
//file to upload | ||
file string | ||
//groupID of artifact | ||
groupID string | ||
//artifactID of artifact | ||
artifactID string | ||
//version of artifact | ||
version string | ||
//hashs the hashs which you want to upload | ||
hash enableHash | ||
} | ||
|
||
var commandLine = &commandLineArgs{} | ||
|
||
//init configuration | ||
func init() { | ||
log.Logger.SetOutput(os.Stdout) | ||
flag.StringVar(&commandLine.urlOfRepository, "repo", "http://localhost/repository/third-party", "url of repository") | ||
flag.StringVar(&commandLine.user, "user", "", "user for repository") | ||
flag.StringVar(&commandLine.password, "password", "", "password for repository") | ||
flag.StringVar(&commandLine.file, "file", "", "your file to upload on repository") | ||
flag.StringVar(&commandLine.groupID, "groupID", "com.jeandeaux", "groupid of artifact") | ||
flag.StringVar(&commandLine.artifactID, "artifactID", "elyne", "artifactID of artifact") | ||
flag.StringVar(&commandLine.version, "version", "0.1.0-SNAPSHOT", "version of artifact") | ||
flag.Var(&commandLine.hash, "hash", "md5 or/and sha1") | ||
flag.Parse() | ||
} | ||
|
||
//main upload artifact | ||
func main() { | ||
|
||
repo := repositorymanager.NewRepository(commandLine.urlOfRepository, commandLine.user, commandLine.password) | ||
|
||
artifact, err := repositorymanager.NewArtifact(commandLine.groupID, commandLine.artifactID, commandLine.version, commandLine.file) | ||
if err != nil { | ||
log.Logger.Fatal(err) | ||
} | ||
|
||
if err := repo.UploadArtifact(artifact, commandLine.hash...); err != nil { | ||
log.Logger.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,264 @@ | ||
//Package repositorymanager upload a file in this repository | ||
package repositorymanager | ||
|
||
import ( | ||
"bytes" | ||
"crypto/md5" | ||
"crypto/sha1" | ||
"encoding/hex" | ||
"fmt" | ||
"hash" | ||
"html/template" | ||
"io" | ||
"net/http" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"net/url" | ||
|
||
"github.com/sjeandeaux/nexus-cli/log" | ||
|
||
"errors" | ||
) | ||
|
||
const ( | ||
dot = "." | ||
suffixPom = "pom" | ||
) | ||
|
||
//Repository where we want put the file | ||
type Repository struct { | ||
url string | ||
user string | ||
password string | ||
client *http.Client | ||
hash map[string]*repositoryHash | ||
} | ||
|
||
// repositoryHash create hash and has the suffix for the file on repository | ||
type repositoryHash struct { | ||
suffix string | ||
//TODO see if we need to a func or variable | ||
hash func() hash.Hash | ||
} | ||
|
||
//NewRepository create a Repository with default client HTTP. | ||
func NewRepository(url, user, password string) *Repository { | ||
const ( | ||
nameMd5 = "md5" | ||
nameSha1 = "sha1" | ||
) | ||
|
||
shaOneAndMdFive := make(map[string]*repositoryHash) | ||
|
||
shaOneAndMdFive[nameMd5] = &repositoryHash{ | ||
suffix: nameMd5, | ||
hash: func() hash.Hash { return md5.New() }, | ||
} | ||
|
||
shaOneAndMdFive[nameSha1] = &repositoryHash{ | ||
suffix: nameSha1, | ||
hash: func() hash.Hash { return sha1.New() }, | ||
} | ||
|
||
return &Repository{ | ||
url: url, | ||
user: user, | ||
password: password, | ||
client: &http.Client{}, | ||
hash: shaOneAndMdFive} | ||
|
||
} | ||
|
||
//UploadArtifact upload ar on repository TODO goroutine to upload | ||
//ar the artifact to upload | ||
//hashs list of hash to send | ||
func (n *Repository) UploadArtifact(ar *Artifact, hashs ...string) error { | ||
pomURL := n.generateURL(ar, suffixPom) | ||
if err := n.upload(pomURL, bytes.NewReader(ar.Pom)); err != nil { | ||
return err | ||
} | ||
|
||
fOpen, err := os.Open(ar.File) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fileURL := n.generateURL(ar, ar.extension()) | ||
if err := n.upload(fileURL, fOpen); err != nil { | ||
return err | ||
} | ||
|
||
for _, h := range hashs { | ||
if iGetIt := n.hash[h]; iGetIt != nil { | ||
n.uploadHash(ar, iGetIt) | ||
} else { | ||
urlIssue := generateURLIssue(h) | ||
log.Logger.Printf("%q is not managed by the client %q", h, urlIssue) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
//generateURLIssue generate the URL on github to create issue on hash method | ||
func generateURLIssue(h string) string { | ||
const ( | ||
title = "Move your ass" | ||
urlFormat = "https://github.com/sjeandeaux/nexus-cli/issues/new?title=%s&body=%s" | ||
bodyFormat = "Could you add the hash %q lazy man?" | ||
) | ||
escapedTitle := url.QueryEscape(title) | ||
body := fmt.Sprintf(bodyFormat, h) | ||
escapedBody := url.QueryEscape(body) | ||
urlIssue := fmt.Sprintf(urlFormat, escapedTitle, escapedBody) | ||
return urlIssue | ||
} | ||
|
||
//generateURL generate the url of ar | ||
// <url>/<groupID/<arID>/<version>/<arID>-<version>.<endOfFile> | ||
func (n *Repository) generateURL(ar *Artifact, endOfFile string) string { | ||
const ( | ||
allReplacement = -1 | ||
slash = "/" | ||
dash = "-" | ||
) | ||
|
||
g := strings.Replace(ar.GroupID, dot, slash, allReplacement) | ||
nameOfFile := fmt.Sprint(slash, ar.ArtifactID, dash, ar.Version, dot, endOfFile) | ||
return fmt.Sprint(n.url, slash, g, slash, ar.ArtifactID, slash, ar.Version, nameOfFile) | ||
} | ||
|
||
//uploadHash upload the hash | ||
func (n *Repository) uploadHash(ar *Artifact, h *repositoryHash) error { | ||
p, f, err := generateHash(ar.Pom, ar.File, h.hash) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
hashedPom := n.generateURL(ar, fmt.Sprint(suffixPom, dot, h.suffix)) | ||
if err = n.upload(hashedPom, p); err != nil { | ||
return err | ||
} | ||
|
||
hashedFile := n.generateURL(ar, fmt.Sprint(ar.extension(), dot, h.suffix)) | ||
return n.upload(hashedFile, f) | ||
} | ||
|
||
func (n *Repository) upload(url string, data io.Reader) error { | ||
const PUT = "PUT" | ||
log.Logger.Print(url) | ||
req, _ := http.NewRequest(PUT, url, data) | ||
if n.user != "" && n.password != "" { | ||
req.SetBasicAuth(n.user, n.password) | ||
} | ||
|
||
res, err := n.client.Do(req) | ||
if err != nil { | ||
return err | ||
} | ||
defer res.Body.Close() | ||
|
||
if res.StatusCode != 201 { | ||
return fmt.Errorf(res.Status) | ||
} | ||
return nil | ||
} | ||
|
||
//generateHash generate the | ||
func generateHash(pom []byte, file string, h func() hash.Hash) (io.Reader, io.Reader, error) { | ||
hashedPom, err := hashSum(bytes.NewReader(pom), h()) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
f, errOnFile := os.Open(file) | ||
defer f.Close() | ||
if errOnFile != nil { | ||
return nil, nil, errOnFile | ||
} | ||
|
||
hashedFile, err := hashSum(f, h()) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
return hashedPom, hashedFile, nil | ||
} | ||
|
||
//generate the hash of io.Reader | ||
func hashSum(data io.Reader, h hash.Hash) (io.Reader, error) { | ||
if _, err := io.Copy(h, data); err != nil { | ||
return nil, err | ||
} | ||
return strings.NewReader(hex.EncodeToString(h.Sum(nil))), nil | ||
} | ||
|
||
//Artifact the artifact | ||
type Artifact struct { | ||
//GroupID of artifact | ||
GroupID string | ||
//ArtifactID of artifact | ||
ArtifactID string | ||
//Version of artifact | ||
Version string | ||
//file to upload | ||
File string | ||
//pom of this artifact | ||
Pom []byte | ||
} | ||
|
||
//NewArtifact create a artifact with this own pom | ||
func NewArtifact(groupID, artifactID, version, file string) (*Artifact, error) { | ||
if file == "" { | ||
return nil, errors.New("You must specify a file") | ||
|
||
} | ||
|
||
if _, err := os.Stat(file); os.IsNotExist(err) { | ||
return nil, err | ||
} | ||
|
||
a := &Artifact{ | ||
GroupID: groupID, | ||
ArtifactID: artifactID, | ||
Version: version, | ||
File: file, | ||
} | ||
|
||
pom, err := a.writePom() | ||
if err != nil { | ||
return nil, err | ||
} | ||
a.Pom = pom | ||
return a, nil | ||
} | ||
|
||
// extension extension of file | ||
func (artifact *Artifact) extension() string { | ||
const unknown = "unknown" | ||
|
||
if ex := filepath.Ext(artifact.File); ex != "" { | ||
return ex[1:] | ||
} | ||
return unknown | ||
} | ||
|
||
// writePom write a wonderful pom | ||
func (artifact *Artifact) writePom() ([]byte, error) { | ||
const templateName = "pom" | ||
const templateValue = `<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>{{.GroupID}}</groupId><artifactId>{{.ArtifactID}}</artifactId><version>{{.Version}}</version></project>` | ||
|
||
pomTemplate, err := template.New(templateName).Parse(templateValue) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var buf bytes.Buffer | ||
err = pomTemplate.Execute(&buf, artifact) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return buf.Bytes(), nil | ||
} |
Oops, something went wrong.