s3_website_monadic 0.0.14 → 0.0.15
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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68d01d8499eba5c41c9b42d0d6ead9ea5386590a
|
4
|
+
data.tar.gz: 5a6381dfa127b1f824c1ded97efe0cb390b179ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e35433d2fb1ad9ce6f737dcfaba2e0b49ca02ab57ae1092e7370ede5e5b50292e19b50236dff44cf5d8ceb76460ccb25a5c1fd15b78e886954616f037ebdafc
|
7
|
+
data.tar.gz: 9bcc6e4226a57017089ddd4e65918a53eee9f3fd3bf3b2c7a2d93542de249fdb4e0c51b762875d2615168721cbcbb847aac31126d23605afe8e46ee7bedca72d
|
data/s3_website.gemspec
CHANGED
@@ -61,7 +61,7 @@ object CloudFront {
|
|
61
61
|
type CloudFrontClientProvider = (Config) => AmazonCloudFront
|
62
62
|
|
63
63
|
case class SuccessfulInvalidation(invalidatedItemsCount: Int) extends SuccessReport {
|
64
|
-
def reportMessage = s"Invalidated ${
|
64
|
+
def reportMessage = s"Invalidated ${invalidatedItemsCount ofType "item"} on CloudFront"
|
65
65
|
}
|
66
66
|
|
67
67
|
case class FailedInvalidation(error: Throwable) extends FailureReport {
|
@@ -71,18 +71,36 @@ object CloudFront {
|
|
71
71
|
def awsCloudFrontClient(config: Config) =
|
72
72
|
new AmazonCloudFrontClient(new BasicAWSCredentials(config.s3_id, config.s3_secret))
|
73
73
|
|
74
|
-
def toInvalidationBatches(pushSuccessReports: Seq[PushSuccessReport])(implicit config: Config): Seq[InvalidationBatch] =
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
74
|
+
def toInvalidationBatches(pushSuccessReports: Seq[PushSuccessReport])(implicit config: Config): Seq[InvalidationBatch] = {
|
75
|
+
val invalidationPaths: Seq[String] = {
|
76
|
+
def withDefaultPathIfNeeded(paths: Seq[String]) = {
|
77
|
+
// This is how we support the Default Root Object @ CloudFront (http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DefaultRootObject.html)
|
78
|
+
// We do this more accurately by fetching the distribution config (http://docs.aws.amazon.com/AmazonCloudFront/latest/APIReference/GetConfig.html)
|
79
|
+
// and reading the Default Root Object from there.
|
80
|
+
val containsPotentialDefaultRootObject = paths
|
81
|
+
.exists(
|
82
|
+
_
|
83
|
+
.replaceFirst("^/", "") // S3 keys do not begin with a slash
|
84
|
+
.contains("/") == false // See if the S3 key is a top-level key (i.e., it is not within a directory)
|
85
|
+
)
|
86
|
+
if (containsPotentialDefaultRootObject) paths :+ "/" else paths
|
87
|
+
}
|
88
|
+
val paths = pushSuccessReports
|
89
|
+
.filter(needsInvalidation) // Assume that redirect objects are never cached.
|
90
|
+
.map(toInvalidationPath)
|
91
|
+
.map (applyInvalidateRootSetting)
|
92
|
+
withDefaultPathIfNeeded(paths)
|
93
|
+
}
|
94
|
+
|
95
|
+
invalidationPaths
|
79
96
|
.grouped(1000) // CloudFront supports max 1000 invalidations in one request (http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html#InvalidationLimits)
|
80
97
|
.map { batchKeys =>
|
81
98
|
new InvalidationBatch() withPaths
|
82
99
|
(new Paths() withItems batchKeys withQuantity batchKeys.size) withCallerReference
|
83
|
-
|
100
|
+
s"s3_website gem ${System.currentTimeMillis()}"
|
84
101
|
}
|
85
102
|
.toSeq
|
103
|
+
}
|
86
104
|
|
87
105
|
def applyInvalidateRootSetting(path: String)(implicit config: Config) =
|
88
106
|
if (config.cloudfront_invalidate_root.exists(_ == true))
|
@@ -156,11 +156,11 @@ object Push {
|
|
156
156
|
"There was nothing to push."
|
157
157
|
case PushCounts(updates, newFiles, failures, redirects, deletes) =>
|
158
158
|
val reportClauses: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer()
|
159
|
-
if (updates > 0) reportClauses += s"Updated ${
|
160
|
-
if (newFiles > 0) reportClauses += s"Created ${
|
161
|
-
if (failures > 0) reportClauses += s"${
|
162
|
-
if (redirects > 0) reportClauses += s"Applied ${
|
163
|
-
if (deletes > 0) reportClauses += s"Deleted ${
|
159
|
+
if (updates > 0) reportClauses += s"Updated ${updates ofType "file"}."
|
160
|
+
if (newFiles > 0) reportClauses += s"Created ${newFiles ofType "file"}."
|
161
|
+
if (failures > 0) reportClauses += s"${failures ofType "operation"} failed." // This includes both failed uploads and deletes.
|
162
|
+
if (redirects > 0) reportClauses += s"Applied ${redirects ofType "redirect"}."
|
163
|
+
if (deletes > 0) reportClauses += s"Deleted ${deletes ofType "file"}."
|
164
164
|
reportClauses.mkString(" ")
|
165
165
|
}
|
166
166
|
|
@@ -51,8 +51,12 @@ package object website {
|
|
51
51
|
httpStatusCode.exists(c => c >= 400 && c < 500)
|
52
52
|
}
|
53
53
|
|
54
|
-
|
55
|
-
def
|
56
|
-
|
54
|
+
implicit class NumReport(val num: Int) extends AnyVal {
|
55
|
+
def ofType(itemType: String) = countToString(num, itemType)
|
56
|
+
|
57
|
+
private def countToString(count: Int, singular: String) = {
|
58
|
+
def plural = s"${singular}s"
|
59
|
+
s"$count ${if (count > 1) plural else singular}"
|
60
|
+
}
|
57
61
|
}
|
58
62
|
}
|
@@ -136,11 +136,11 @@ class S3WebsiteSpec extends Specification {
|
|
136
136
|
"invalidate the updated CloudFront items" in new SiteDirectory with MockAWS {
|
137
137
|
implicit val site = siteWithFiles(
|
138
138
|
config = defaultConfig.copy(cloudfront_distribution_id = Some("EGM1J2JJX9Z")),
|
139
|
-
localFiles = "test.css" :: "articles/index.html" :: Nil
|
139
|
+
localFiles = "css/test.css" :: "articles/index.html" :: Nil
|
140
140
|
)
|
141
|
-
setOutdatedS3Keys("test.css", "articles/index.html")
|
141
|
+
setOutdatedS3Keys("css/test.css", "articles/index.html")
|
142
142
|
Push.pushSite
|
143
|
-
sentInvalidationRequest.getInvalidationBatch.getPaths.getItems.toSeq.sorted must equalTo(("/test.css" :: "/articles/index.html" :: Nil).sorted)
|
143
|
+
sentInvalidationRequest.getInvalidationBatch.getPaths.getItems.toSeq.sorted must equalTo(("/css/test.css" :: "/articles/index.html" :: Nil).sorted)
|
144
144
|
}
|
145
145
|
|
146
146
|
"not send CloudFront invalidation requests on new objects" in new SiteDirectory with MockAWS {
|
@@ -191,23 +191,37 @@ class S3WebsiteSpec extends Specification {
|
|
191
191
|
Push.pushSite
|
192
192
|
sentInvalidationRequest.getInvalidationBatch.getPaths.getItems.toSeq.sorted must equalTo(("/articles/arnold's%20file.html" :: Nil).sorted)
|
193
193
|
}
|
194
|
+
|
195
|
+
/*
|
196
|
+
* Because CloudFront supports Default Root Objects (http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DefaultRootObject.html),
|
197
|
+
* we have to guess
|
198
|
+
*/
|
199
|
+
"invalidate the root object '/' if a top-level object is updated or deleted" in new SiteDirectory with MockAWS {
|
200
|
+
implicit val site = siteWithFiles(
|
201
|
+
config = defaultConfig.copy(cloudfront_distribution_id = Some("EGM1J2JJX9Z")),
|
202
|
+
localFiles = "maybe-index.html" :: Nil
|
203
|
+
)
|
204
|
+
setOutdatedS3Keys("maybe-index.html")
|
205
|
+
Push.pushSite
|
206
|
+
sentInvalidationRequest.getInvalidationBatch.getPaths.getItems.toSeq.sorted must equalTo(("/" :: "/maybe-index.html" :: Nil).sorted)
|
207
|
+
}
|
194
208
|
}
|
195
209
|
|
196
210
|
"cloudfront_invalidate_root: true" should {
|
197
211
|
"convert CloudFront invalidation paths with the '/index.html' suffix into '/'" in new SiteDirectory with MockAWS {
|
198
212
|
implicit val site = siteWithFiles(
|
199
213
|
config = defaultConfig.copy(cloudfront_distribution_id = Some("EGM1J2JJX9Z"), cloudfront_invalidate_root = Some(true)),
|
200
|
-
localFiles = "
|
214
|
+
localFiles = "articles/index.html" :: Nil
|
201
215
|
)
|
202
|
-
setOutdatedS3Keys("
|
216
|
+
setOutdatedS3Keys("articles/index.html")
|
203
217
|
Push.pushSite
|
204
|
-
sentInvalidationRequest.getInvalidationBatch.getPaths.getItems.toSeq.sorted must equalTo(("/
|
218
|
+
sentInvalidationRequest.getInvalidationBatch.getPaths.getItems.toSeq.sorted must equalTo(("/articles/" :: Nil).sorted)
|
205
219
|
}
|
206
220
|
}
|
207
221
|
|
208
222
|
"a site with over 1000 items" should {
|
209
223
|
"split the CloudFront invalidation requests into batches of 1000 items" in new SiteDirectory with MockAWS {
|
210
|
-
val files = (1 to 1002).map { i => s"file-$i"}
|
224
|
+
val files = (1 to 1002).map { i => s"lots-of-files/file-$i"}
|
211
225
|
implicit val site = siteWithFiles(
|
212
226
|
config = defaultConfig.copy(cloudfront_distribution_id = Some("EGM1J2JJX9Z")),
|
213
227
|
localFiles = files
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: s3_website_monadic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lauri Lehmijoki
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|