s3_website_monadic 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f36d81a978b21bdb205386ffe7b805d2ac3c0ae
4
- data.tar.gz: 022c4ed32cbe3a433d32e43a5b1c71344885aad7
3
+ metadata.gz: 001860d8f4b29eae3c6d2f4e71d4e815a09bd068
4
+ data.tar.gz: 2c39928790f622d404855dc548858bd06960c46a
5
5
  SHA512:
6
- metadata.gz: 32c75ffe6fc5976b59b437a8c65eac3a9be89ffb8f59f1f0c19bb599087eac5674ddbe81e651eb71c4aa1cd2807ac78fb47da1089b1a4dc5b07623fb245d30e4
7
- data.tar.gz: 2ac550438e430c5361ddf005dda7a07d4d099d4fb6bada1dafc88e8cf51252d1cbe8910458d86acbf0dcd650b0efefe05e7415312f335a852a04c128ff2f2952
6
+ metadata.gz: 1c33fa0f3299e3852a67bc2267f9afc8b6895833f9ce5007f5615aca50080f443fbe4f1ef84b92a36d062790179e3819686f1e797b4c8851b9e8340f5dd6d0d1
7
+ data.tar.gz: 620e2e04c5d145b2e86be58662c5669223f446ab480d8dd5259209c8b6ed2c0ea476d058160a0c545bee0677c766b608dfe5f997033c06e85446af2c0a99de0a
data/s3_website.gemspec CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "s3_website_monadic"
6
- s.version = "0.0.3"
6
+ s.version = "0.0.4"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Lauri Lehmijoki"]
9
9
  s.email = ["lauri.lehmijoki@iki.fi"]
@@ -9,6 +9,12 @@ import scala.collection.JavaConversions._
9
9
  import scala.concurrent.duration._
10
10
  import s3.website.S3.{SuccessfulUpload, PushSuccessReport}
11
11
  import com.amazonaws.auth.BasicAWSCredentials
12
+ import s3.website.Logger._
13
+ import s3.website.S3.SuccessfulUpload
14
+ import scala.util.Failure
15
+ import s3.website.CloudFront.SuccessfulInvalidation
16
+ import scala.util.Success
17
+ import s3.website.CloudFront.FailedInvalidation
12
18
 
13
19
  class CloudFront(implicit cfClient: CloudFrontClientProvider, sleepUnit: TimeUnit) {
14
20
 
@@ -18,7 +24,7 @@ class CloudFront(implicit cfClient: CloudFrontClientProvider, sleepUnit: TimeUni
18
24
  val invalidationReq = new CreateInvalidationRequest(distributionId, invalidationBatch)
19
25
  cfClient(config).createInvalidation(invalidationReq)
20
26
  val result = SuccessfulInvalidation(invalidationBatch.getPaths.getItems.size())
21
- println(s"Invalidated ${result.invalidatedItemsCount} item(s) on the CloudFront distribution $distributionId.")
27
+ info(result)
22
28
  result
23
29
  } recoverWith {
24
30
  case e: TooManyInvalidationsInProgressException =>
@@ -26,7 +32,7 @@ class CloudFront(implicit cfClient: CloudFrontClientProvider, sleepUnit: TimeUni
26
32
  (fibs drop attempt).head min 15, /* AWS docs way that invalidations complete in 15 minutes */
27
33
  sleepUnit
28
34
  )
29
- println(maxInvalidationsExceededInfo)
35
+ pending(maxInvalidationsExceededInfo)
30
36
  Thread.sleep(duration.toMillis)
31
37
  tryInvalidate(attempt + 1)
32
38
  }
@@ -35,8 +41,9 @@ class CloudFront(implicit cfClient: CloudFrontClientProvider, sleepUnit: TimeUni
35
41
  case Success(res) =>
36
42
  Right(res)
37
43
  case Failure(err) =>
38
- println(s"Failed to invalidate the CloudFront distribution $distributionId (${err.getMessage})")
39
- Left(FailedInvalidation())
44
+ val report = FailedInvalidation(err)
45
+ info(report)
46
+ Left(report)
40
47
  }
41
48
  }
42
49
 
@@ -61,9 +68,13 @@ object CloudFront {
61
68
 
62
69
  type CloudFrontClientProvider = (Config) => AmazonCloudFront
63
70
 
64
- case class SuccessfulInvalidation(invalidatedItemsCount: Int)
71
+ case class SuccessfulInvalidation(invalidatedItemsCount: Int) extends SuccessReport {
72
+ def reportMessage = s"Invalidated $invalidatedItemsCount item(s) on CloudFront"
73
+ }
65
74
 
66
- case class FailedInvalidation()
75
+ case class FailedInvalidation(error: Throwable) extends FailureReport{
76
+ def reportMessage = s"Failed to invalidate the CloudFront distribution (${error.getMessage})"
77
+ }
67
78
 
68
79
  def awsCloudFrontClient(config: Config) =
69
80
  new AmazonCloudFrontClient(new BasicAWSCredentials(config.s3_id, config.s3_secret))
@@ -23,6 +23,15 @@ import s3.website.S3.SuccessfulDelete
23
23
  import s3.website.CloudFront.SuccessfulInvalidation
24
24
  import s3.website.S3.SuccessfulUpload
25
25
  import s3.website.CloudFront.FailedInvalidation
26
+ import s3.website.Logger._
27
+ import s3.website.S3.SuccessfulDelete
28
+ import s3.website.CloudFront.SuccessfulInvalidation
29
+ import s3.website.S3.SuccessfulUpload
30
+ import s3.website.CloudFront.FailedInvalidation
31
+ import s3.website.S3.SuccessfulDelete
32
+ import s3.website.CloudFront.SuccessfulInvalidation
33
+ import s3.website.S3.SuccessfulUpload
34
+ import s3.website.CloudFront.FailedInvalidation
26
35
 
27
36
  object Push {
28
37
 
@@ -33,7 +42,7 @@ object Push {
33
42
  cloudFrontClientProvider: CloudFrontClientProvider = CloudFront.awsCloudFrontClient,
34
43
  cloudFrontSleepTimeUnit: TimeUnit = MINUTES
35
44
  ): ExitCode = {
36
- println(s"Deploying ${site.rootDirectory}/* to ${site.config.s3_bucket}")
45
+ info(s"Deploying ${site.rootDirectory}/* to ${site.config.s3_bucket}")
37
46
  val utils: Utils = new Utils
38
47
 
39
48
  val errorsOrReports = for {
@@ -93,11 +102,10 @@ object Push {
93
102
  def afterPushFinished(errorsOrFinishedUploads: Either[Error, FinishedPushOperations], invalidationSucceeded: Option[Boolean])(implicit config: Config): ExitCode = {
94
103
  errorsOrFinishedUploads.right.foreach { finishedUploads =>
95
104
  val pushCounts = pushCountsToString(resolvePushCounts(finishedUploads))
96
- println(s"$pushCounts")
97
- println(s"Go visit: http://${config.s3_bucket}.${config.s3_endpoint.s3WebsiteHostname}")
105
+ info(s"Summary: $pushCounts")
98
106
  }
99
- errorsOrFinishedUploads.left foreach (err => println(s"Failed to push the site: ${err.message}"))
100
- errorsOrFinishedUploads.fold(
107
+ errorsOrFinishedUploads.left foreach (err => fail(s"Encountered error: ${err.message}"))
108
+ val exitCode = errorsOrFinishedUploads.fold(
101
109
  _ => 1,
102
110
  finishedUploads => finishedUploads.foldLeft(0) { (memo, finishedUpload) =>
103
111
  memo + finishedUpload.fold(
@@ -109,6 +117,12 @@ object Push {
109
117
  ) max invalidationSucceeded.fold(0)(allInvalidationsSucceeded =>
110
118
  if (allInvalidationsSucceeded) 0 else 1
111
119
  )
120
+
121
+ if (exitCode == 0)
122
+ info(s"Successfully pushed the website to http://${config.s3_bucket}.${config.s3_endpoint.s3WebsiteHostname}")
123
+ else
124
+ fail(s"Failed to push the website to http://${config.s3_bucket}.${config.s3_endpoint.s3WebsiteHostname}")
125
+ exitCode
112
126
  }
113
127
 
114
128
  def awaitForUploads(uploadReports: PushReports)(implicit executor: ExecutionContextExecutor): FinishedPushOperations =
@@ -180,7 +194,7 @@ object Push {
180
194
  threadPool.shutdownNow()
181
195
  pushStatus
182
196
  }
183
- errorOrPushStatus.left foreach (err => println(s"Could not load the site: ${err.message}"))
197
+ errorOrPushStatus.left foreach (err => fail(s"Could not load the site: ${err.message}"))
184
198
  System.exit(errorOrPushStatus.fold(_ => 1, pushStatus => pushStatus))
185
199
  }
186
200
  }
@@ -17,6 +17,16 @@ import scala.Some
17
17
  import s3.website.model.IOError
18
18
  import scala.util.Success
19
19
  import s3.website.model.UserError
20
+ import s3.website.Logger._
21
+ import s3.website.S3.SuccessfulUpload
22
+ import s3.website.S3.SuccessfulDelete
23
+ import s3.website.S3.FailedUpload
24
+ import scala.util.Failure
25
+ import scala.Some
26
+ import s3.website.S3.FailedDelete
27
+ import s3.website.model.IOError
28
+ import scala.util.Success
29
+ import s3.website.model.UserError
20
30
 
21
31
  class S3(implicit s3Client: S3ClientProvider) {
22
32
 
@@ -24,7 +34,7 @@ class S3(implicit s3Client: S3ClientProvider) {
24
34
  Future {
25
35
  s3Client(config) putObject toPutObjectRequest(upload)
26
36
  val report = SuccessfulUpload(upload)
27
- println(report.reportMessage)
37
+ info(report)
28
38
  Right(report)
29
39
  } recover usingErrorHandler { error =>
30
40
  FailedUpload(upload.s3Key, error)
@@ -34,7 +44,7 @@ class S3(implicit s3Client: S3ClientProvider) {
34
44
  Future {
35
45
  s3Client(config) deleteObject(config.s3_bucket, s3Key)
36
46
  val report = SuccessfulDelete(s3Key)
37
- println(report.reportMessage)
47
+ info(report)
38
48
  Right(report)
39
49
  } recover usingErrorHandler { error =>
40
50
  FailedDelete(s3Key, error)
@@ -43,7 +53,7 @@ class S3(implicit s3Client: S3ClientProvider) {
43
53
  def usingErrorHandler[T <: PushFailureReport, F <: PushFailureReport](f: (Throwable) => T): PartialFunction[Throwable, Either[T, F]] = {
44
54
  case error =>
45
55
  val report = f(error)
46
- println(report.reportMessage)
56
+ info(report)
47
57
  Left(report)
48
58
  }
49
59
 
@@ -104,12 +114,8 @@ object S3 {
104
114
  summaries
105
115
  }
106
116
 
107
- sealed trait PushItemReport {
108
- def reportMessage: String
109
- }
110
-
111
- sealed trait PushFailureReport extends PushItemReport
112
- sealed trait PushSuccessReport extends PushItemReport {
117
+ sealed trait PushFailureReport extends FailureReport
118
+ sealed trait PushSuccessReport extends SuccessReport {
113
119
  def s3Key: String
114
120
  }
115
121
 
@@ -11,3 +11,68 @@ class Utils(implicit config: Config) {
11
11
  parallelSeq
12
12
  }
13
13
  }
14
+
15
+ object Logger {
16
+ import Rainbow._
17
+ def info(msg: String) = println(s"[${"info".blue}] $msg")
18
+ def fail(msg: String) = println(s"[${"fail".red}] $msg")
19
+
20
+ def info(report: SuccessReport) = println(s"[${"succ".green}] ${report.reportMessage}")
21
+ def info(report: FailureReport) = fail(report.reportMessage)
22
+
23
+ def pending(msg: String) = println(s"[${"wait".yellow}] $msg")
24
+ }
25
+
26
+ /**
27
+ * Idea copied from https://github.com/ktoso/scala-rainbow.
28
+ */
29
+ object Rainbow {
30
+ implicit class RainbowString(val s: String) extends AnyVal {
31
+ import Console._
32
+
33
+ /** Colorize the given string foreground to ANSI black */
34
+ def black = BLACK + s + RESET
35
+ /** Colorize the given string foreground to ANSI red */
36
+ def red = RED + s + RESET
37
+ /** Colorize the given string foreground to ANSI red */
38
+ def green = GREEN + s + RESET
39
+ /** Colorize the given string foreground to ANSI red */
40
+ def yellow = YELLOW + s + RESET
41
+ /** Colorize the given string foreground to ANSI red */
42
+ def blue = BLUE + s + RESET
43
+ /** Colorize the given string foreground to ANSI red */
44
+ def magenta = MAGENTA + s + RESET
45
+ /** Colorize the given string foreground to ANSI red */
46
+ def cyan = CYAN + s + RESET
47
+ /** Colorize the given string foreground to ANSI red */
48
+ def white = WHITE + s + RESET
49
+
50
+ /** Colorize the given string background to ANSI red */
51
+ def onBlack = BLACK_B + s + RESET
52
+ /** Colorize the given string background to ANSI red */
53
+ def onRed = RED_B+ s + RESET
54
+ /** Colorize the given string background to ANSI red */
55
+ def onGreen = GREEN_B+ s + RESET
56
+ /** Colorize the given string background to ANSI red */
57
+ def onYellow = YELLOW_B + s + RESET
58
+ /** Colorize the given string background to ANSI red */
59
+ def onBlue = BLUE_B+ s + RESET
60
+ /** Colorize the given string background to ANSI red */
61
+ def onMagenta = MAGENTA_B + s + RESET
62
+ /** Colorize the given string background to ANSI red */
63
+ def onCyan = CYAN_B+ s + RESET
64
+ /** Colorize the given string background to ANSI red */
65
+ def onWhite = WHITE_B+ s + RESET
66
+
67
+ /** Make the given string bold */
68
+ def bold = BOLD + s + RESET
69
+ /** Underline the given string */
70
+ def underlined = UNDERLINED + s + RESET
71
+ /** Make the given string blink (some terminals may turn this off) */
72
+ def blink = BLINK + s + RESET
73
+ /** Reverse the ANSI colors of the given string */
74
+ def reversed = REVERSED + s + RESET
75
+ /** Make the given string invisible using ANSI color codes */
76
+ def invisible = INVISIBLE + s + RESET
77
+ }
78
+ }
@@ -1,11 +1,15 @@
1
1
  package s3.website.model
2
2
 
3
3
  import java.io.File
4
- import scala.util.{Failure, Success, Try}
4
+ import scala.util.Try
5
5
  import org.yaml.snakeyaml.Yaml
6
6
  import s3.website.model.Config._
7
7
  import scala.io.Source.fromFile
8
8
  import scala.language.postfixOps
9
+ import s3.website.Logger._
10
+ import scala.util.Failure
11
+ import s3.website.model.Config.UnsafeYaml
12
+ import scala.util.Success
9
13
 
10
14
  case class Site(rootDirectory: String, config: Config) {
11
15
  def resolveS3Key(file: File) = file.getAbsolutePath.replace(rootDirectory, "").replaceFirst("^/", "")
@@ -38,8 +42,8 @@ object Site {
38
42
  concurrency_level <- loadOptionalInt("concurrency_level").right
39
43
  redirects <- loadRedirects.right
40
44
  } yield {
41
- gzip_zopfli.foreach(_ => println("zopfli is not currently supported"))
42
- extensionless_mime_type.foreach(_ => println(
45
+ gzip_zopfli.foreach(_ => info("zopfli is not currently supported"))
46
+ extensionless_mime_type.foreach(_ => info(
43
47
  s"Ignoring the extensionless_mime_type setting in $yamlConfigPath. Counting on Apache Tika to infer correct mime types.")
44
48
  )
45
49
  Config(
@@ -0,0 +1,10 @@
1
+ package s3
2
+
3
+ package object website {
4
+ trait Report {
5
+ def reportMessage: String
6
+ }
7
+ trait SuccessReport extends Report
8
+
9
+ trait FailureReport extends Report
10
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s3_website_monadic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lauri Lehmijoki
@@ -378,6 +378,7 @@ files:
378
378
  - src/main/scala/s3/website/model/Site.scala
379
379
  - src/main/scala/s3/website/model/errors.scala
380
380
  - src/main/scala/s3/website/model/push.scala
381
+ - src/main/scala/s3/website/package.scala
381
382
  - src/test/scala/s3/website/S3WebsiteSpec.scala
382
383
  homepage: https://github.com/laurilehmijoki/s3_website
383
384
  licenses: