s3_website_monadic 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: