s3_website 2.9.0 → 2.10.0

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: ee583948eaac40a396bdd7dcce3ac0f17b026b53
4
- data.tar.gz: fb3b7ff28372c6844d2c637f59b8fbc1a08a112e
3
+ metadata.gz: a869e0bbb5276a123020d7ae96f52d729d56b166
4
+ data.tar.gz: b6b51944723aaf3f1c22f949a56261137cc74dcc
5
5
  SHA512:
6
- metadata.gz: a06324e37ab33faa10ca761537336020dc2c712b980facfad0aece7fc3c010fafb1c2782c4878a5b566a85d3f5ca357756abfe9f1207847f3cd1b93ec7b23336
7
- data.tar.gz: b7db3637d2582366540f0938f8fe3608340b1b74ff6ba308db40da17f794061fd382dedcdde8af090ac1713f182e27c2c5161bd8c7333dd25c993e3a025556d4
6
+ metadata.gz: 2f3705e5c621c1b44225e8b3f7070496d59d258780f268b3d4183d709e5d988041d26d47a9a8bffdaac89d6f86c5b8e3caff99afafd18d1cfaa1f3cceb7ea99b
7
+ data.tar.gz: d13a8bd0492c4cc10e92bc4bd08ecf71eded8f0bac47ffa7bee15b9bd4909de2dcae7ce3e92d80aead594fcbe0eb13d747dc0fdf11517beb4f5b62397a5351f9
data/README.md CHANGED
@@ -126,6 +126,15 @@ Here's an example:
126
126
  cache_control: public, no-transform, max-age=1200, s-maxage=1200
127
127
  ```
128
128
 
129
+ You can also specify a hash of globs, and all files matching those globs will have
130
+ the specified cache-control string:
131
+
132
+ ```yaml
133
+ cache_control:
134
+ "assets/*": public, max-age=3600
135
+ "*": no-cache, no-store
136
+ ```
137
+
129
138
  After changing the `cache_control` setting, push with the `--force` option.
130
139
  Force-pushing allows you to update the S3 object metadata of existing files.
131
140
 
data/changelog.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  This project uses [Semantic Versioning](http://semver.org).
4
4
 
5
+ ## 2.10.0
6
+
7
+ * Support glob hashes in `cache_control`
8
+
5
9
  ## 2.9.0
6
10
 
7
11
  * Add setting `cache_control`
@@ -1,3 +1,3 @@
1
1
  module S3Website
2
- VERSION = '2.9.0'
2
+ VERSION = '2.10.0'
3
3
  end
@@ -72,7 +72,7 @@ object S3 {
72
72
  md setContentLength uploadFile.length
73
73
  md setContentType contentType
74
74
  upload.encodingOnS3.map(_ => "gzip") foreach md.setContentEncoding
75
- val cacheControl: Option[String] = (upload.maxAge, config.cache_control) match {
75
+ val cacheControl: Option[String] = (upload.maxAge, upload.cacheControl) match {
76
76
  case (maxAge: Some[Int], cacheCtrl: Some[String]) =>
77
77
  logger.warn("Overriding the max_age setting with the cache_control setting")
78
78
  cacheCtrl
@@ -15,7 +15,7 @@ case class Config(
15
15
  s3_endpoint: S3Endpoint,
16
16
  site: Option[String],
17
17
  max_age: Option[Either[Int, Map[String, Int]]],
18
- cache_control: Option[String],
18
+ cache_control: Option[Either[String, Map[String, String]]],
19
19
  gzip: Option[Either[Boolean, Seq[String]]],
20
20
  gzip_zopfli: Option[Boolean],
21
21
  ignore_on_server: Option[Either[String, Seq[String]]],
@@ -83,6 +83,20 @@ object Config {
83
83
  yamlValue getOrElse Left(ErrorReport(s"The key $key has to have an int or (string -> int) value"))
84
84
  }
85
85
 
86
+ def loadCacheControl(implicit unsafeYaml: UnsafeYaml): Either[ErrorReport, Option[Either[String, Map[String, String]]]] = {
87
+ val key = "cache_control"
88
+ val yamlValue = for {
89
+ cacheControlOption <- loadOptionalValue(key)
90
+ } yield {
91
+ Right(cacheControlOption.map {
92
+ case cacheControl if cacheControl.isInstanceOf[String] => Left(cacheControl.asInstanceOf[String])
93
+ case cacheControl if cacheControl.isInstanceOf[java.util.Map[_,_]] => Right(cacheControl.asInstanceOf[java.util.Map[String,String]].toMap) // TODO an unsafe call to asInstanceOf
94
+ })
95
+ }
96
+
97
+ yamlValue getOrElse Left(ErrorReport(s"The key $key has to have a string or (string -> string) value"))
98
+ }
99
+
86
100
  def loadEndpoint(implicit unsafeYaml: UnsafeYaml): Either[ErrorReport, Option[S3Endpoint]] =
87
101
  loadOptionalString("s3_endpoint").right flatMap { endpointString =>
88
102
  endpointString.map(S3Endpoint.forString) match {
@@ -40,7 +40,7 @@ object Site {
40
40
  s3_endpoint <- loadEndpoint.right
41
41
  site <- loadOptionalString("site").right
42
42
  max_age <- loadMaxAge.right
43
- cache_control <- loadOptionalString("cache_control").right
43
+ cache_control <- loadCacheControl.right
44
44
  gzip <- loadOptionalBooleanOrStringSeq("gzip").right
45
45
  gzip_zopfli <- loadOptionalBoolean("gzip_zopfli").right
46
46
  extensionless_mime_type <- loadOptionalString("extensionless_mime_type").right
@@ -94,6 +94,29 @@ case class Upload(originalFile: File, uploadType: UploadType)(implicit site: Sit
94
94
  }
95
95
  }
96
96
 
97
+ lazy val cacheControl: Option[String] = {
98
+ type GlobsMap = Map[String, String]
99
+ site.config.cache_control.flatMap { (intOrGlobs: Either[String, GlobsMap]) =>
100
+ type GlobsSeq = Seq[(String, String)]
101
+ def respectMostSpecific(globs: GlobsMap): GlobsSeq = globs.toSeq.sortBy(_._1.length).reverse
102
+ intOrGlobs
103
+ .right.map(respectMostSpecific)
104
+ .fold(
105
+ (cacheCtrl: String) => Some(cacheCtrl),
106
+ (globs: GlobsSeq) => {
107
+ val matchingCacheControl = (glob: String, cacheControl: String) =>
108
+ rubyRuntime.evalScriptlet(
109
+ s"""|# encoding: utf-8
110
+ |File.fnmatch('$glob', "$s3Key")""".stripMargin)
111
+ .toJava(classOf[Boolean])
112
+ .asInstanceOf[Boolean]
113
+ val fileGlobMatch = globs find Function.tupled(matchingCacheControl)
114
+ fileGlobMatch map (_._2)
115
+ }
116
+ )
117
+ }
118
+ }
119
+
97
120
  /**
98
121
  * May throw an exception, so remember to call this in a Try or Future monad
99
122
  */
@@ -507,6 +507,56 @@ class S3WebsiteSpec extends Specification {
507
507
  ))
508
508
  logEntries must contain("[\u001B[33mwarn\u001B[0m] Overriding the max_age setting with the cache_control settin")
509
509
  }
510
+
511
+ "supports all valid URI characters in the glob setting" in new BasicSetup {
512
+ config = """
513
+ |cache_control:
514
+ | "*.html": public, max-age=120
515
+ """.stripMargin
516
+ val allValidUrlCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=" // See http://stackoverflow.com/a/1547940/990356 for discussion
517
+ setLocalFile(s"$allValidUrlCharacters.html")
518
+ push()
519
+ sentPutObjectRequest.getMetadata.getCacheControl must equalTo("public, max-age=120")
520
+ }
521
+
522
+ "be applied to files that match the glob" in new BasicSetup {
523
+ config = """
524
+ |cache_control:
525
+ | "*.html": no-store
526
+ """.stripMargin
527
+ setLocalFile("index.html")
528
+ push()
529
+ sentPutObjectRequest.getMetadata.getCacheControl must equalTo("no-store")
530
+ }
531
+
532
+ "be applied to directories that match the glob" in new BasicSetup {
533
+ config = """
534
+ |cache_control:
535
+ | "assets/**/*.js": no-cache, no-store
536
+ """.stripMargin
537
+ setLocalFile("assets/lib/jquery.js")
538
+ push()
539
+ sentPutObjectRequest.getMetadata.getCacheControl must equalTo("no-cache, no-store")
540
+ }
541
+
542
+ "not be applied if the glob doesn't match" in new BasicSetup {
543
+ config = """
544
+ |cache_control:
545
+ | "*.js": max-age=120
546
+ """.stripMargin
547
+ setLocalFile("index.html")
548
+ push()
549
+ sentPutObjectRequest.getMetadata.getCacheControl must beNull
550
+ }
551
+
552
+ "support non-US-ASCII directory names" in new BasicSetup {
553
+ config = """
554
+ |cache_control:
555
+ | "*": no-cache
556
+ """.stripMargin
557
+ setLocalFile("tags/笔记/index.html")
558
+ push() must equalTo(0)
559
+ }
510
560
  }
511
561
 
512
562
  "cache control" can {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s3_website
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.0
4
+ version: 2.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lauri Lehmijoki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-03 00:00:00.000000000 Z
11
+ date: 2015-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor