s3_website 2.14.0 → 2.14.1

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: ed60d795c8498eaa376cf3db07a1d150e664fb94
4
- data.tar.gz: eb092f1524a34883201452b5ed013a864901d866
3
+ metadata.gz: 3bbec93340ef359945d7d3cfbe80883d68375991
4
+ data.tar.gz: 5bdcd5868373b3864e4dd5e5632cf3776a4c2486
5
5
  SHA512:
6
- metadata.gz: 08ec5fdda103891fef1dd85b5319cd5572fd021048cceb1aae4fee438800462e072b6bcac45408fa8110f8dc59845cc98ed9eaa42a0229d0eec2ce8936dcd806
7
- data.tar.gz: aab6bd5d66dafc38a200756c26a5da9e5334a35ec26f2947c1db1f6fc08dd91ed3054afc86057e126136adb63da34d673ee9dbe05da20f23ffeb06812909e3d7
6
+ metadata.gz: 8c1ce8a06185665f9c5069ef5a116c596928bed0b0045e8ab8fb4ca0a2e83c40897229b8581705f15907840cca5d2bbffc97d6d9735d1f1444645fcbd7b44cf9
7
+ data.tar.gz: 626d786f95ed0678bc13fddc544c37a8775f7e3856d7dbb9e158da8ac06fee042288323f4b5296e24ee517ea04ca8f93f98486abd698fef407902762df74c674
data/README.md CHANGED
@@ -72,6 +72,11 @@ in the project's root directory to take advantage of this feature. Please have
72
72
  a look at [dotenv's usage guide](https://github.com/bkeepers/dotenv#usage) for
73
73
  syntax information.
74
74
 
75
+ Your `.env` file should containing the following variables:
76
+
77
+ AWS_ACCESS_KEY_ID=FOO
78
+ AWS_SECRET_ACCESS_KEY=BAR
79
+
75
80
  ## Project goals
76
81
 
77
82
  * Provide a command-line interface tool for deploying and managing S3 websites
@@ -169,6 +174,9 @@ not the pre-processed extensions.
169
174
 
170
175
  After changing the `gzip` setting, push with the `--force` option.
171
176
 
177
+ s3_website will not gzip a file that is already gzipped. This is useful in the
178
+ situations where your build tools gzip a file before you invoke `s3_website push`.
179
+
172
180
  ### Using non-standard AWS regions
173
181
 
174
182
  By default, `s3_website` uses the US Standard Region. You can upload your
@@ -185,7 +193,10 @@ s3_endpoint: ap-northeast-1
185
193
  The valid `s3_endpoint` values consist of the [S3 location constraint
186
194
  values](http://docs.amazonwebservices.com/general/latest/gr/rande.html#s3_region).
187
195
 
188
- Note that at the moment s3_website does not support the *eu-central-1* region.
196
+ Note that at the moment s3_website does not support any region that
197
+ supports only a V4 Signature and does not support V2
198
+ (i.e. *eu-central-1*, *ap-south-1*, *ap-northeast-2*).
199
+ This support can be tracked in [issue #126](https://github.com/laurilehmijoki/s3_website/issues/126).
189
200
 
190
201
  ### Ignoring files you want to keep on AWS
191
202
 
data/changelog.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  This project uses [Semantic Versioning](http://semver.org).
4
4
 
5
+ ## 2.14.1
6
+
7
+ * Do not gzip a file that is already gzipped
8
+
9
+ See <https://github.com/laurilehmijoki/s3_website/issues/229> for discussion
10
+
5
11
  ## 2.14.0
6
12
 
7
13
  * Add support for CloudFront wildcard invalidations
@@ -1,3 +1,3 @@
1
1
  module S3Website
2
- VERSION = '2.14.0'
2
+ VERSION = '2.14.1'
3
3
  end
@@ -1 +1 @@
1
- 6736177c885c454c20caadf2396980f0
1
+ 53be05bebd606f3d1e2443beb13130a5
@@ -2,15 +2,20 @@ package s3.website.model
2
2
 
3
3
  import com.amazonaws.services.s3.model.S3ObjectSummary
4
4
  import java.io._
5
+
5
6
  import org.apache.commons.codec.digest.DigestUtils
6
- import java.util.zip.GZIPOutputStream
7
+ import java.util.zip.{GZIPInputStream, GZIPOutputStream}
8
+
7
9
  import org.apache.tika.Tika
8
10
  import s3.website.Ruby._
9
11
  import s3.website._
10
12
  import s3.website.model.Upload.tika
11
13
  import s3.website.model.Encoding.encodingOnS3
12
14
  import java.io.File.createTempFile
15
+
16
+ import org.apache.commons.io.FileUtils
13
17
  import org.apache.commons.io.IOUtils.copy
18
+
14
19
  import scala.concurrent.{ExecutionContextExecutor, Future}
15
20
  import scala.util.Try
16
21
 
@@ -51,7 +56,7 @@ case object RedirectFile extends UploadType {
51
56
  val pushAction = Redirected
52
57
  }
53
58
 
54
- case class Upload(originalFile: File, uploadType: UploadType)(implicit site: Site) {
59
+ case class Upload(originalFile: File, uploadType: UploadType)(implicit site: Site, logger: Logger) {
55
60
  lazy val s3Key = site.resolveS3Key(originalFile)
56
61
 
57
62
  lazy val encodingOnS3 = Encoding.encodingOnS3(s3Key)
@@ -96,21 +101,37 @@ case class Upload(originalFile: File, uploadType: UploadType)(implicit site: Sit
96
101
  object Upload {
97
102
  lazy val tika = Try(new Tika())
98
103
 
99
- def md5(originalFile: File)(implicit site: Site): Try[MD5] =
104
+ def md5(originalFile: File)(implicit site: Site, logger: Logger): Try[MD5] =
100
105
  uploadFile(originalFile) map { file =>
101
106
  using(fis { file }) { DigestUtils.md5Hex }
102
107
  }
103
108
 
104
- def uploadFile(originalFile: File)(implicit site: Site): Try[File] =
109
+ def uploadFile(originalFile: File)(implicit site: Site, logger: Logger): Try[File] =
105
110
  encodingOnS3(site resolveS3Key originalFile)
106
111
  .fold(Try(originalFile))(algorithm =>
107
112
  Try {
108
- val tempFile = createTempFile(originalFile.getName, "gzip")
109
- tempFile.deleteOnExit()
110
- using(new GZIPOutputStream(new FileOutputStream(tempFile))) { stream =>
111
- copy(fis(originalFile), stream)
113
+ val isAlreadyGzipped =
114
+ if (originalFile.length() < 2) {
115
+ false
116
+ } else {
117
+ val fis = new FileInputStream(originalFile)
118
+ val amountOfMagicGzipBytes = 2
119
+ val firstTwoBytes = Array.fill[Byte](amountOfMagicGzipBytes)(0)
120
+ fis.read(firstTwoBytes, 0, amountOfMagicGzipBytes)
121
+ val head = firstTwoBytes(0) & 0xff | (firstTwoBytes(1) << 8) & 0xff00
122
+ head == GZIPInputStream.GZIP_MAGIC
123
+ }
124
+ if (isAlreadyGzipped) {
125
+ logger.debug(s"File ${originalFile.getAbsolutePath} is already gzipped. Skipping gzip.")
126
+ originalFile
127
+ } else {
128
+ val tempFile = createTempFile(originalFile.getName, "gzip")
129
+ tempFile.deleteOnExit()
130
+ using(new GZIPOutputStream(new FileOutputStream(tempFile))) { stream =>
131
+ copy(fis(originalFile), stream)
132
+ }
133
+ tempFile
112
134
  }
113
- tempFile
114
135
  }
115
136
  )
116
137
 
@@ -1,7 +1,9 @@
1
1
  package s3.website
2
2
 
3
- import java.io.File
3
+ import java.io._
4
+ import java.nio.charset.StandardCharsets
4
5
  import java.util.concurrent.atomic.AtomicInteger
6
+ import java.util.zip.{GZIPInputStream, GZIPOutputStream}
5
7
 
6
8
  import com.amazonaws.AmazonServiceException
7
9
  import com.amazonaws.services.cloudfront.AmazonCloudFront
@@ -9,8 +11,9 @@ import com.amazonaws.services.cloudfront.model.{CreateInvalidationRequest, Creat
9
11
  import com.amazonaws.services.s3.AmazonS3
10
12
  import com.amazonaws.services.s3.model._
11
13
  import org.apache.commons.codec.digest.DigestUtils._
12
- import org.apache.commons.io.FileUtils
13
14
  import org.apache.commons.io.FileUtils._
15
+ import org.apache.commons.io.IOUtils.{write => _}
16
+ import org.apache.commons.io.{FileUtils, IOUtils}
14
17
  import org.mockito.Mockito._
15
18
  import org.mockito.invocation.InvocationOnMock
16
19
  import org.mockito.stubbing.Answer
@@ -18,9 +21,9 @@ import org.mockito.{ArgumentCaptor, Matchers, Mockito}
18
21
  import org.specs2.mutable.{BeforeAfter, Specification}
19
22
  import org.specs2.specification.Scope
20
23
  import s3.website.CloudFront.CloudFrontSetting
21
- import s3.website.UploadHelper.DELETE_NOTHING_MAGIC_WORD
22
- import s3.website.Push.{CliArgs}
24
+ import s3.website.Push.CliArgs
23
25
  import s3.website.S3.S3Setting
26
+ import s3.website.UploadHelper.DELETE_NOTHING_MAGIC_WORD
24
27
  import s3.website.model.Config.S3_website_yml
25
28
  import s3.website.model.Ssg.automaticallySupportedSiteGenerators
26
29
  import s3.website.model._
@@ -41,6 +44,52 @@ class S3WebsiteSpec extends Specification {
41
44
  sentPutObjectRequest.getKey must equalTo("styles.css")
42
45
  }
43
46
 
47
+ "gzips a file" in new BasicSetup {
48
+ val htmlString = "<h1>hi again</h1>"
49
+ val gzippedBytes = gzip(htmlString.getBytes(StandardCharsets.UTF_8))
50
+ config = "gzip: true"
51
+ setLocalFileWithContent("index.html", gzippedBytes)
52
+ setS3File("styles.css", "1c5117e5839ad8fc00ce3c41296255a1" /* md5 of the gzip of the file contents */)
53
+ val putObjectRequestCaptor = ArgumentCaptor.forClass(classOf[PutObjectRequest])
54
+ push()
55
+ sentPutObjectRequest.getKey must equalTo("index.html")
56
+ verify(amazonS3Client).putObject(putObjectRequestCaptor.capture())
57
+
58
+ val bytesToS3: InputStream = putObjectRequestCaptor.getValue.getInputStream
59
+ val unzippedBytesToS3 = new GZIPInputStream(bytesToS3)
60
+ val unzippedString = IOUtils.toString(unzippedBytesToS3, StandardCharsets.UTF_8)
61
+
62
+ unzippedString must equalTo(htmlString)
63
+ }
64
+
65
+ "not gzip the file if it's already gzipped" in new BasicSetup {
66
+ config = "gzip: true"
67
+
68
+ val cssString = "body { color: red }"
69
+ val gzippedCss = gzip(cssString.getBytes(StandardCharsets.UTF_8))
70
+ setLocalFileWithContent("styles.css", gzippedCss)
71
+ val putObjectRequestCaptor = ArgumentCaptor.forClass(classOf[PutObjectRequest])
72
+ push()
73
+ sentPutObjectRequest.getKey must equalTo("styles.css")
74
+ verify(amazonS3Client).putObject(putObjectRequestCaptor.capture())
75
+
76
+ val bytesToS3: InputStream = putObjectRequestCaptor.getValue.getInputStream
77
+ val unzippedBytesToS3 = new GZIPInputStream(bytesToS3)
78
+ val unzippedString = IOUtils.toString(unzippedBytesToS3, StandardCharsets.UTF_8)
79
+
80
+ unzippedString must equalTo(cssString)
81
+ }
82
+
83
+ def gzip(data: Array[Byte]): Array[Byte] = {
84
+ def using[T <: Closeable, R](cl: T)(f: (T) => R): R = try f(cl) finally cl.close()
85
+
86
+ val gzippedOutputStream: ByteArrayOutputStream = new ByteArrayOutputStream
87
+ using(new GZIPOutputStream(gzippedOutputStream)) { stream =>
88
+ IOUtils.copy(new ByteArrayInputStream(data), stream)
89
+ }
90
+ gzippedOutputStream.toByteArray
91
+ }
92
+
44
93
  "not update a gzipped S3 object if the contents has not changed" in new BasicSetup {
45
94
  config = "gzip: true"
46
95
  setLocalFileWithContent(("styles.css", "<h1>hi</h1>"))
@@ -1343,6 +1392,13 @@ class S3WebsiteSpec extends Specification {
1343
1392
  write(file, fileNameAndContent._2)
1344
1393
  }
1345
1394
 
1395
+ def setLocalFileWithContent(fileName: String, contents: Array[Byte]) = {
1396
+ val file = new File(siteDirectory, fileName)
1397
+ forceMkdir(file.getParentFile)
1398
+ file.createNewFile()
1399
+ FileUtils.writeByteArrayToFile(file, contents)
1400
+ }
1401
+
1346
1402
  var config = ""
1347
1403
  val baseConfig =
1348
1404
  """
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.14.0
4
+ version: 2.14.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lauri Lehmijoki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-07 00:00:00.000000000 Z
11
+ date: 2016-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor