Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added credentials providers support #21

Merged
merged 5 commits into from
Mar 19, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 42 additions & 15 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,31 +33,35 @@ In `project/plugins.sbt`:
```scala
resolvers += "Era7 maven releases" at "http://releases.era7.com.s3.amazonaws.com"

addSbtPlugin("ohnosequences" % "sbt-s3-resolver" % "0.9.0")
addSbtPlugin("ohnosequences" % "sbt-s3-resolver" % "0.10.0")
```


### Setting keys

| Key | Type | Default |
| ------------------: | :--------------------------: | :------------------------------ |
| `s3credentialsFile` | `File` | `~/.sbt/.s3credentials` |
| `s3credentials` | `S3Credentials` | parsed from `s3credentialsFile` |
| `s3credentials` | `AWSCredentialsProvider` | parsed from `s3credentialsFile` |
| `s3region` | `Region` | `EU_Ireland` |
| `s3overwrite` | `Boolean` | same as `isSnapshot` key |
| `s3resolver` | `(String, s3) => S3Resolver` | is set using all above |

Note that `S3Credentials` type is just `(String, String)` and by `Region` type we mean `com.amazonaws.services.s3.model.Region`.
Where

```scala
type Region = com.amazonaws.services.s3.model.Region
type AWSCredentialsProvider = com.amazonaws.auth.AWSCredentialsProvider
```

To add these defaults to your project add to `build.sbt`

```scala
S3Resolver.settings
S3Resolver.defaults

// then you can adjust these settings if you need
```

You can just use `s3resolver` setting key, which takes the name and S3 bucket url and returns `S3Resolver` which is implicitly converted to `sbt.Resolver`.
You can just use `s3resolver` setting key that takes a _name_ and an _S3 bucket url_ and returns `S3Resolver` which is implicitly converted to `sbt.Resolver`.


### Publishing
Expand Down Expand Up @@ -90,23 +94,46 @@ resolvers ++= Seq(

### Credentials

By default, credentials (the access key and secret key of your AWS account (or that of an IAM user)) are expected to be in the `~/.sbt/.s3credentials` file in the following format:
#### Types of credentials providers

```
accessKey = 322wasa923...
secretKey = 2342xasd8fDfaa9C...
```
`s3credentials` key has the [`AWSCredentialsProvider`](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/AWSCredentialsProvider.html) type from AWS Java SDK, so it can be

* `file("/some/absolute/path/to/credentials.properties")` which will be implicitly converted to the [`PropertiesFileCredentialsProvider`](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/PropertiesFileCredentialsProvider.html)
* [`new EnvironmentVariableCredentialsProvider()`](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/EnvironmentVariableCredentialsProvider.html) which looks for credentials in the environment variables
* [`new InstanceProfileCredentialsProvider()`](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/InstanceProfileCredentialsProvider.html) which loads credentials from the Amazon EC2 Instance Metadata Service
* [`new SystemPropertiesCredentialsProvider()`](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/SystemPropertiesCredentialsProvider.html) which looks for credentials at the `aws.accessKeyId` and `aws.secretKey` Java system properties
* Some other types of credentials providers which you can find in the [AWS Java SDK docs](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/AWSCredentialsProvider.html)

If you want to store your credentials somewhere else, you can set it in your `build.sbt` (after `S3Resolver.settings`):
Note that for using them you will need to add `import com.amazonaws.auth._` to the beginning of your `build.sbt`.

#### Combining credentials providers

You can combine several credentials providers with the `|` ("or") operator, which will construct the [`AWSCredentialsProviderChain`](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/AWSCredentialsProviderChain.html). For example the **default credentials** chain in this plugin is

```scala
s3credentialsFile := Some("/funny/absolute/path/to/credentials.properties")
s3credentials := {
file(System.getProperty("user.home")) / ".sbt" / ".s3credentials" |
new EnvironmentVariableCredentialsProvider() |
new SystemPropertiesCredentialsProvider()
}
```

> don't forget to **add your credentials file to `.gitignore`**, so that you won't publish this file anywhere
It means that the plugin looks for credentials in the following places (in this particular order):

As soon as you set `s3credentialsFile`, the `s3credentials` key contains the parsed credentials from that file.
1. Property file `~/.sbt/.s3credentials` of the following format:

```properties
accessKey = 322wasa923...
secretKey = 2342xasd8fDfaa9C...
```
2. Environment Variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_KEY`
3. Java System Properties: `aws.accessKeyId` and `aws.secretKey`

You can check which credentials are loaded with the `showS3Credentials` task:

```bash
sbt showS3Credentials
```

### Patterns

Expand Down
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ crossBuildingSettings
CrossBuilding.crossSbtVersions := Seq("0.12", "0.13")


S3Resolver.settings
S3Resolver.defaults

publishMavenStyle := true

Expand All @@ -45,4 +45,4 @@ resolvers ++= Seq (
, "Era7 maven snapshots" at "http://snapshots.era7.com.s3.amazonaws.com"
)

libraryDependencies += "ohnosequences" %% "ivy-s3-resolver" % "0.3.0"
libraryDependencies += "ohnosequences" %% "ivy-s3-resolver" % "0.4.0"
1 change: 1 addition & 0 deletions notes/0.10.0.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Changed type of `s3credentials` key to [`AWSCredentialsProvider`](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/AWSCredentialsProvider.html) from the AWS Java SDK. See #20, #21 and the updated Readme section about using credentials.
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=0.12.4
sbt.version=0.13.1
4 changes: 2 additions & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ resolvers ++= Seq(
, "Era7 maven snapshots" at "http://snapshots.era7.com.s3.amazonaws.com"
)

// addSbtPlugin("ohnosequences" % "sbt-s3-resolver" % "0.8.0")
addSbtPlugin("ohnosequences" % "sbt-s3-resolver" % "0.9.0-SNAPSHOT")
// addSbtPlugin("ohnosequences" % "sbt-s3-resolver" % "0.9.0")
addSbtPlugin("ohnosequences" % "sbt-s3-resolver" % "0.10.0-SNAPSHOT")

addSbtPlugin("com.github.gseitz" % "sbt-release" % "0.8.2")

Expand Down
67 changes: 37 additions & 30 deletions src/main/scala/SBTS3Resolver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,22 @@ package ohnosequences.sbt

import sbt._
import Keys._
// import com.amazonaws.services.s3.model.Region;
import com.amazonaws.auth._

object SbtS3Resolver extends Plugin {

type S3Credentials = (String, String)
type Region = com.amazonaws.services.s3.model.Region
type AWSCredentialsProvider = com.amazonaws.auth.AWSCredentialsProvider

lazy val s3credentialsFile = SettingKey[File]("s3credentialsFile", "Properties format file with amazon credentials to access S3")
lazy val s3credentials = SettingKey[S3Credentials]("s3credentials", "S3 credentials accessKey and secretKey")
lazy val s3credentials = SettingKey[AWSCredentialsProvider]("s3credentials", "AWS credentials provider to access S3")
lazy val s3region = SettingKey[Region]("s3region", "AWS Region for your S3 resolvers")
lazy val s3overwrite = SettingKey[Boolean]("s3overwrite", "Controls whether publishing resolver can overwrite artifacts")
lazy val s3resolver = SettingKey[(String, s3) => S3Resolver]("s3resolver", "Takes name and bucket url and returns an S3 resolver")
lazy val showS3Credentials = TaskKey[Unit]("showS3Credentials", "Just outputs credentials that are loaded by the s3credentials provider")


def s3credentialsParser(file: File): S3Credentials = {
if (!file.exists)
sys.error("[WARN] File with S3 credentials doesn't exist: " + file + "; S3 resolvers won't work!")
else {
val p = new java.util.Properties
p.load(new java.io.FileInputStream(file))
val creds = (p.getProperty("accessKey"), p.getProperty("secretKey"))
// println("[info] S3 credentials were loaded from " + file)
creds
}
}

type Region = com.amazonaws.services.s3.model.Region

// S3 bucket url
case class s3(url: String) {
// adds s3:// prefix if it was not there
// adds 's3://' prefix if it was not there
override def toString: String = "s3://" + url.stripPrefix("s3://")

// convenience method, to use normal bucket addresses with `at`
Expand All @@ -40,9 +26,9 @@ object SbtS3Resolver extends Plugin {
}

case class S3Resolver
(credentials: S3Credentials, overwrite: Boolean, region: Region)
(credentialsProvider: AWSCredentialsProvider, overwrite: Boolean, region: Region)
(name: String, url: s3)
extends ohnosequences.ivy.S3Resolver(name, credentials._1, credentials._2, overwrite, region) {
extends ohnosequences.ivy.S3Resolver(name, credentialsProvider, overwrite, region) {

def withPatterns(patterns: Patterns): S3Resolver = {
if (patterns.isMavenCompatible) this.setM2compatible(true)
Expand All @@ -59,21 +45,42 @@ object SbtS3Resolver extends Plugin {
def withMavenPatterns = withPatterns(Resolver.mavenStylePatterns)
}

// Converting S3Resolver to the standard sbt Resolver
implicit def toSbtResolver(s3r: S3Resolver): Resolver = {
if (s3r.getIvyPatterns.isEmpty || s3r.getArtifactPatterns.isEmpty)
s3r withPatterns Resolver.defaultPatterns

new sbt.RawRepository(s3r)
}

object S3Resolver {
lazy val settings = Seq[Setting[_]](
s3credentialsFile := file(System.getProperty("user.home")) / ".sbt" / ".s3credentials",
s3credentials <<= s3credentialsFile (s3credentialsParser),
s3region := com.amazonaws.services.s3.model.Region.EU_Ireland,
s3overwrite <<= isSnapshot,
// Just extending AWSCredentialsProvider with | method for combining them in a chain
case class ExtCredentialsProvider(val provider: AWSCredentialsProvider) {
def |(another: AWSCredentialsProvider) = new AWSCredentialsProviderChain(provider, another)
}
implicit def toAmazonProvider(e: ExtCredentialsProvider): AWSCredentialsProvider = e.provider

s3resolver <<= (s3credentials, s3overwrite, s3region) (S3Resolver.apply)
// Converts file to AWSCredentialsProvider (treating it as a properties file)
implicit def fileToCredsProvider(f: File) = new PropertiesFileCredentialsProvider(f.getAbsolutePath)

// Converts anything that can be AWSCredentialsProvider to the extended thing
implicit def toExtProvider[P](p: P)(implicit prov: P => AWSCredentialsProvider) = ExtCredentialsProvider(prov(p))

// Default settings
object S3Resolver {
lazy val defaults = Seq[Setting[_]](
s3credentials := {
file(System.getProperty("user.home")) / ".sbt" / ".s3credentials" |
new EnvironmentVariableCredentialsProvider() |
new SystemPropertiesCredentialsProvider()
},
s3region := com.amazonaws.services.s3.model.Region.EU_Ireland,
s3overwrite <<= isSnapshot,
s3resolver <<= (s3credentials, s3overwrite, s3region) (S3Resolver.apply),
showS3Credentials <<= (s3credentials, streams) map { (provider, str) =>
val creds = provider.getCredentials
str.log.info("AWS credentials loaded in 's3credentials' setting key:")
str.log.info("Access key: " + creds.getAWSAccessKeyId)
str.log.info("Secret key: " + creds.getAWSSecretKey)
}
)

}
Expand Down
31 changes: 19 additions & 12 deletions src/test/resources/test-a/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,27 @@ scalaVersion := "2.10.2"

publishMavenStyle := false

publishTo <<= (isSnapshot, s3credentials) {
(snapshot, credentials) =>
credentials map S3Resolver(
name = "s3 resolver"
, url = "s3://test2.frutero.org"
, patterns = Resolver.ivyStylePatterns
, overwrite = snapshot
).toSbtResolver
publishTo <<= (isSnapshot, s3credentialsProvider, s3region) {
(snapshot, s3prov, s3reg) =>
Some(toSbtResolver(S3Resolver(
s3prov,
overwrite = snapshot,
s3reg)(
name = "s3 resolver",
url = s3("s3://test2.frutero.org")
)))
}

resolvers <++= s3credentials { cs => Seq(
S3Resolver("Snapshots resolver", "s3://test2.frutero.org")
) map {r => cs map r.toSbtResolver} flatten
}
s3region := com.amazonaws.services.s3.model.Region.EU_Ireland

s3credentials <<= s3credentialsFile (s3credentialsParser)

s3credentialsProvider <<= s3credentials(staticProvider)

//resolvers <++= s3credentials { cs => Seq(
// S3Resolver("Snapshots resolver", "s3://test2.frutero.org")
// ) map {r => cs map r.toSbtResolver} flatten
//}


resolvers ++= Seq (
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/test-a/project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=0.12.4
2 changes: 1 addition & 1 deletion src/test/resources/test-a/project/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ resolvers ++= Seq (
"ohnosequences Snapshots" at "http://snapshots.era7.com.s3.amazonaws.com"
)

addSbtPlugin("ohnosequences" % "sbt-s3-resolver" % "0.7.0-SNAPSHOT")
addSbtPlugin("ohnosequences" % "sbt-s3-resolver" % "0.10.1-SNAPSHOT")



2 changes: 1 addition & 1 deletion version.sbt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version in ThisBuild := "0.10.0-SNAPSHOT"
version in ThisBuild := "0.11.0-SNAPSHOT"