s3_website_monadic 0.0.26 → 0.0.27

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: b5b1aa15a1ce62e1a349ace807b4a1a3222330ed
4
- data.tar.gz: fa293c4a5a8178f60a17049633722a940505a7e1
3
+ metadata.gz: f19d0eae1ea4ae3a515bc6f26066a2a90b241d58
4
+ data.tar.gz: 3c8762e1cda26b3f84021b3a071c75c61f1f6e87
5
5
  SHA512:
6
- metadata.gz: a9b80ed77c9504d795ff67ad5e6ba7151beea0749037b73656c0d2a9128215df3077eaed594f2851cc969ef285f11d1fe98775644df15b86e7cc96be56c2e060
7
- data.tar.gz: fcacbb3ea86be21b97900781735fd5d119df26a4cec709feada0a225f51c5c76dc5926953b9a92e103ed74dc50a4e81211a39b26274c36dbabf238f105093b0e
6
+ metadata.gz: 0eb150f681d4cb2efd22a35a26ee55df9fe4575e560b82a17a0043161deea72a2979839679aec20d3bfefe400a2a46389a93378f346b3da7d55597b34a44d394
7
+ data.tar.gz: 5937ab122bf4014de4073c1796c4f43cadd38488e2d893d8715cbfeebd3acb6e3a0808976bbd630aeaa03609c0f58e0a8426ad9f8ccc9f58208139e75b1b9b7e
@@ -53,6 +53,12 @@ class Cli < Thor
53
53
  :default => Dir.pwd,
54
54
  :desc => "The directory where your config file is. When not defined, s3_website will look in the current working directory."
55
55
  )
56
+ option(
57
+ :verbose,
58
+ :type => :boolean,
59
+ :default => false,
60
+ :desc => "Print verbose output"
61
+ )
56
62
  desc 'push', 'Push local files with the S3 website'
57
63
  long_desc <<-LONGDESC
58
64
  `s3_website push` will upload new and changes files to S3. It will
@@ -61,10 +67,11 @@ class Cli < Thor
61
67
  def push
62
68
  call_dir = Dir.pwd
63
69
  project_root = File.expand_path(File.dirname(__FILE__)+ '/..')
70
+ logger = Logger.new(options[:verbose])
64
71
  Dir.chdir(project_root) {
65
- jar_file = resolve_jar project_root
72
+ jar_file = resolve_jar project_root, logger
66
73
  # Then run it
67
- run_s3_website_jar(jar_file, call_dir)
74
+ run_s3_website_jar(jar_file, call_dir, logger)
68
75
  }
69
76
  end
70
77
 
@@ -72,11 +79,11 @@ class Cli < Thor
72
79
  subcommand 'cfg', Cfg
73
80
  end
74
81
 
75
- def run_s3_website_jar(jar_file, call_dir)
82
+ def run_s3_website_jar(jar_file, call_dir, logger)
76
83
  site_path = File.expand_path(S3Website::Paths.infer_site_path options[:site], call_dir)
77
84
  config_dir = File.expand_path options[:config_dir]
78
- args = "--site=#{site_path} --config-dir=#{config_dir}"
79
- debug_msg "Using #{jar_file}"
85
+ args = "--site=#{site_path} --config-dir=#{config_dir} #{'--verbose' if options[:verbose]}"
86
+ logger.debug_msg "Using #{jar_file}"
80
87
  if system("java -cp #{jar_file} s3.website.Push #{args}")
81
88
  exit 0
82
89
  else
@@ -84,7 +91,7 @@ def run_s3_website_jar(jar_file, call_dir)
84
91
  end
85
92
  end
86
93
 
87
- def resolve_jar(project_root)
94
+ def resolve_jar(project_root, logger)
88
95
  development_jar_path =
89
96
  project_root + '/target/scala-2.11/s3_website.jar'
90
97
  released_jar_lookup_paths = [
@@ -103,26 +110,25 @@ def resolve_jar(project_root)
103
110
  is_development = File.exists?(project_root + '/.git')
104
111
  if is_development
105
112
  system "./sbt assembly"
106
- puts development_jar_path
107
113
  development_jar_path
108
114
  else
109
- download_jar(released_jar_lookup_paths)
115
+ download_jar(released_jar_lookup_paths, logger)
110
116
  end
111
117
  end
112
118
  end
113
119
 
114
- def download_jar(released_jar_lookup_paths)
120
+ def download_jar(released_jar_lookup_paths, logger)
115
121
  tag_name = "v#{S3Website::VERSION}"
116
122
  downloaded_jar = released_jar_lookup_paths.select { |jar_path|
117
123
  File.writable? File.dirname(jar_path)
118
124
  }.first
119
125
  unless downloaded_jar
120
- fail_msg "Neither #{released_jar_lookup_paths.join ' or '} is writable. Cannot download s3_website.jar."
121
- fail_msg "Set either directory as writable to the current user and try again."
126
+ logger.fail_msg "Neither #{released_jar_lookup_paths.join ' or '} is writable. Cannot download s3_website.jar."
127
+ logger.fail_msg "Set either directory as writable to the current user and try again."
122
128
  exit 1
123
129
  end
124
130
  download_url = "https://github.com/laurilehmijoki/s3_website/releases/download/#{tag_name}/s3_website.jar"
125
- info_msg "Downloading #{download_url} into #{downloaded_jar}"
131
+ logger.info_msg "Downloading #{download_url} into #{downloaded_jar}"
126
132
  require 'open-uri'
127
133
  open(downloaded_jar, 'wb') do |file|
128
134
  file << open(download_url).read
@@ -130,20 +136,31 @@ def download_jar(released_jar_lookup_paths)
130
136
  downloaded_jar
131
137
  end
132
138
 
133
- def debug_msg(msg)
134
- print_msg 'debg'.cyan, msg
135
- end
139
+ class Logger
140
+ attr_reader :verbose
141
+ def initialize(verbose)
142
+ @verbose = verbose
143
+ end
136
144
 
137
- def info_msg(msg)
138
- print_msg 'info'.blue, msg
139
- end
145
+ def debug_msg(msg)
146
+ if verbose
147
+ print_msg 'debg'.cyan, msg
148
+ end
149
+ end
140
150
 
141
- def fail_msg(msg)
142
- print_msg 'fail'.red, msg
143
- end
151
+ def info_msg(msg)
152
+ print_msg 'info'.blue, msg
153
+ end
154
+
155
+ def fail_msg(msg)
156
+ print_msg 'fail'.red, msg
157
+ end
158
+
159
+ private
144
160
 
145
- def print_msg(prefix, msg)
146
- puts "[#{prefix}] #{msg}"
161
+ def print_msg(prefix, msg)
162
+ puts "[#{prefix}] #{msg}"
163
+ end
147
164
  end
148
165
 
149
166
  Cli.start(ARGV)
@@ -1,3 +1,3 @@
1
1
  module S3Website
2
- VERSION = '0.0.26'
2
+ VERSION = '0.0.27'
3
3
  end
@@ -8,12 +8,11 @@ import scala.collection.JavaConversions._
8
8
  import scala.concurrent.duration._
9
9
  import s3.website.S3.{SuccessfulDelete, PushSuccessReport, SuccessfulUpload}
10
10
  import com.amazonaws.auth.BasicAWSCredentials
11
- import s3.website.Logger._
12
11
  import java.net.URI
13
12
  import Utils._
14
13
  import scala.concurrent.{ExecutionContextExecutor, Future}
15
14
 
16
- class CloudFront(implicit cloudFrontSettings: CloudFrontSettings, config: Config) {
15
+ class CloudFront(implicit cloudFrontSettings: CloudFrontSettings, config: Config, logger: Logger) {
17
16
  val cloudFront = cloudFrontSettings.cfClient(config)
18
17
 
19
18
  def invalidate(invalidationBatch: InvalidationBatch, distributionId: String, attempt: Attempt = 1)
@@ -22,7 +21,7 @@ class CloudFront(implicit cloudFrontSettings: CloudFrontSettings, config: Config
22
21
  val invalidationReq = new CreateInvalidationRequest(distributionId, invalidationBatch)
23
22
  cloudFront.createInvalidation(invalidationReq)
24
23
  val result = SuccessfulInvalidation(invalidationBatch.getPaths.getItems.size())
25
- info(result)
24
+ logger.info(result)
26
25
  Right(result)
27
26
  } recoverWith (tooManyInvalidationsRetry(invalidationBatch, distributionId, attempt) orElse retry(attempt)(
28
27
  createFailureReport = error => FailedInvalidation(error),
@@ -30,13 +29,13 @@ class CloudFront(implicit cloudFrontSettings: CloudFrontSettings, config: Config
30
29
  ))
31
30
 
32
31
  def tooManyInvalidationsRetry(invalidationBatch: InvalidationBatch, distributionId: String, attempt: Attempt)
33
- (implicit ec: ExecutionContextExecutor): PartialFunction[Throwable, InvalidationResult] = {
32
+ (implicit ec: ExecutionContextExecutor, logger: Logger): PartialFunction[Throwable, InvalidationResult] = {
34
33
  case e: TooManyInvalidationsInProgressException =>
35
34
  val duration: Duration = Duration(
36
35
  (fibs drop attempt).head min 15, /* CloudFront invalidations complete within 15 minutes */
37
36
  cloudFrontSettings.retryTimeUnit
38
37
  )
39
- pending(maxInvalidationsExceededInfo(duration, attempt))
38
+ logger.pending(maxInvalidationsExceededInfo(duration, attempt))
40
39
  Thread.sleep(duration.toMillis)
41
40
  invalidate(invalidationBatch, distributionId, attempt + 1)
42
41
  }
@@ -13,13 +13,11 @@ import s3.website.model.LocalFile.resolveLocalFiles
13
13
  import scala.collection.parallel.ParSeq
14
14
  import java.util.concurrent.ExecutorService
15
15
  import s3.website.model._
16
- import s3.website.Implicits._
17
16
  import s3.website.model.Update
18
17
  import s3.website.model.NewFile
19
18
  import s3.website.S3.PushSuccessReport
20
19
  import scala.collection.mutable.ArrayBuffer
21
20
  import s3.website.CloudFront._
22
- import s3.website.Logger._
23
21
  import s3.website.S3.SuccessfulDelete
24
22
  import s3.website.CloudFront.SuccessfulInvalidation
25
23
  import s3.website.S3.S3Settings
@@ -33,10 +31,11 @@ object Push {
33
31
  implicit site: Site,
34
32
  executor: ExecutionContextExecutor,
35
33
  s3Settings: S3Settings,
36
- cloudFrontSettings: CloudFrontSettings
34
+ cloudFrontSettings: CloudFrontSettings,
35
+ logger: Logger
37
36
  ): ExitCode = {
38
- info(s"Deploying ${site.rootDirectory}/* to ${site.config.s3_bucket}")
39
- val utils: Utils = new Utils
37
+ logger.info(s"Deploying ${site.rootDirectory}/* to ${site.config.s3_bucket}")
38
+ val utils = new Utils
40
39
 
41
40
  val redirects = Redirect.resolveRedirects
42
41
  val redirectResults = redirects.map(new S3() upload(_))
@@ -64,7 +63,7 @@ object Push {
64
63
 
65
64
  def invalidateCloudFrontItems
66
65
  (errorsOrFinishedPushOps: Either[ErrorReport, FinishedPushOperations])
67
- (implicit config: Config, cloudFrontSettings: CloudFrontSettings, ec: ExecutionContextExecutor): Option[InvalidationSucceeded] = {
66
+ (implicit config: Config, cloudFrontSettings: CloudFrontSettings, ec: ExecutionContextExecutor, logger: Logger): Option[InvalidationSucceeded] = {
68
67
  config.cloudfront_distribution_id.map {
69
68
  distributionId =>
70
69
  val pushSuccessReports = errorsOrFinishedPushOps.fold(
@@ -101,12 +100,13 @@ object Push {
101
100
 
102
101
  type InvalidationSucceeded = Boolean
103
102
 
104
- def afterPushFinished(errorsOrFinishedUploads: Either[ErrorReport, FinishedPushOperations], invalidationSucceeded: Option[Boolean])(implicit config: Config): ExitCode = {
103
+ def afterPushFinished(errorsOrFinishedUploads: Either[ErrorReport, FinishedPushOperations], invalidationSucceeded: Option[Boolean])
104
+ (implicit config: Config, logger: Logger): ExitCode = {
105
105
  errorsOrFinishedUploads.right.foreach { finishedUploads =>
106
106
  val pushCounts = pushCountsToString(resolvePushCounts(finishedUploads))
107
- info(s"Summary: $pushCounts")
107
+ logger.info(s"Summary: $pushCounts")
108
108
  }
109
- errorsOrFinishedUploads.left foreach (err => fail(s"Encountered an error: ${err.reportMessage}"))
109
+ errorsOrFinishedUploads.left foreach (err => logger.fail(s"Encountered an error: ${err.reportMessage}"))
110
110
  val exitCode = errorsOrFinishedUploads.fold(
111
111
  _ => 1,
112
112
  finishedUploads => finishedUploads.foldLeft(0) { (memo, finishedUpload) =>
@@ -121,9 +121,9 @@ object Push {
121
121
  )
122
122
 
123
123
  if (exitCode == 0)
124
- info(s"Successfully pushed the website to http://${config.s3_bucket}.${config.s3_endpoint.s3WebsiteHostname}")
124
+ logger.info(s"Successfully pushed the website to http://${config.s3_bucket}.${config.s3_endpoint.s3WebsiteHostname}")
125
125
  else
126
- fail(s"Failed to push the website to http://${config.s3_bucket}.${config.s3_endpoint.s3WebsiteHostname}")
126
+ logger.fail(s"Failed to push the website to http://${config.s3_bucket}.${config.s3_endpoint.s3WebsiteHostname}")
127
127
  exitCode
128
128
  }
129
129
 
@@ -181,20 +181,21 @@ object Push {
181
181
 
182
182
  @Option def site: String
183
183
  @Option(longName = Array("config-dir")) def configDir: String
184
-
184
+ @Option def verbose: Boolean
185
185
  }
186
186
 
187
187
  def main(args: Array[String]) {
188
188
  val cliArgs = CliFactory.parseArguments(classOf[CliArgs], args:_*)
189
189
  implicit val s3Settings = S3Settings()
190
190
  implicit val cloudFrontSettings = CloudFrontSettings()
191
+ implicit val logger: Logger = new Logger(cliArgs.verbose)
191
192
  val errorOrPushStatus = push(siteInDirectory = cliArgs.site, withConfigDirectory = cliArgs.configDir)
192
- errorOrPushStatus.left foreach (err => fail(s"Could not load the site: ${err.reportMessage}"))
193
+ errorOrPushStatus.left foreach (err => logger.fail(s"Could not load the site: ${err.reportMessage}"))
193
194
  System exit errorOrPushStatus.fold(_ => 1, pushStatus => pushStatus)
194
195
  }
195
196
 
196
197
  def push(siteInDirectory: String, withConfigDirectory: String)
197
- (implicit s3Settings: S3Settings, cloudFrontSettings: CloudFrontSettings) =
198
+ (implicit s3Settings: S3Settings, cloudFrontSettings: CloudFrontSettings, logger: Logger) =
198
199
  loadSite(withConfigDirectory + "/s3_website.yml", siteInDirectory)
199
200
  .right
200
201
  .map {
@@ -7,7 +7,6 @@ import com.amazonaws.services.s3.model._
7
7
  import scala.collection.JavaConversions._
8
8
  import scala.concurrent.{ExecutionContextExecutor, Future}
9
9
  import com.amazonaws.services.s3.model.StorageClass.ReducedRedundancy
10
- import s3.website.Logger._
11
10
  import scala.concurrent.duration.TimeUnit
12
11
  import java.util.concurrent.TimeUnit.SECONDS
13
12
  import s3.website.S3.SuccessfulUpload
@@ -19,23 +18,25 @@ import s3.website.S3.S3Settings
19
18
 
20
19
  class S3(implicit s3Settings: S3Settings, executor: ExecutionContextExecutor) {
21
20
 
22
- def upload(upload: Upload with UploadTypeResolved, a: Attempt = 1)(implicit config: Config): Future[Either[FailedUpload, SuccessfulUpload]] =
21
+ def upload(upload: Upload with UploadTypeResolved, a: Attempt = 1)
22
+ (implicit config: Config, logger: Logger): Future[Either[FailedUpload, SuccessfulUpload]] =
23
23
  Future {
24
24
  val putObjectRequest = toPutObjectRequest(upload)
25
25
  s3Settings.s3Client(config) putObject putObjectRequest
26
26
  val report = SuccessfulUpload(upload, putObjectRequest)
27
- info(report)
27
+ logger.info(report)
28
28
  Right(report)
29
29
  } recoverWith retry(a)(
30
30
  createFailureReport = error => FailedUpload(upload.s3Key, error),
31
31
  retryAction = newAttempt => this.upload(upload, newAttempt)
32
32
  )
33
33
 
34
- def delete(s3Key: String, a: Attempt = 1)(implicit config: Config): Future[Either[FailedDelete, SuccessfulDelete]] =
34
+ def delete(s3Key: String, a: Attempt = 1)
35
+ (implicit config: Config, logger: Logger): Future[Either[FailedDelete, SuccessfulDelete]] =
35
36
  Future {
36
37
  s3Settings.s3Client(config) deleteObject(config.s3_bucket, s3Key)
37
38
  val report = SuccessfulDelete(s3Key)
38
- info(report)
39
+ logger.info(report)
39
40
  Right(report)
40
41
  } recoverWith retry(a)(
41
42
  createFailureReport = error => FailedDelete(s3Key, error),
@@ -83,9 +84,9 @@ object S3 {
83
84
 
84
85
  def resolveS3FilesAndUpdates(localFiles: Seq[LocalFile])
85
86
  (nextMarker: Option[String] = None, alreadyResolved: Seq[S3File] = Nil, attempt: Attempt = 1, onFlightUpdateFutures: UpdateFutures = Nil)
86
- (implicit config: Config, s3Settings: S3Settings, ec: ExecutionContextExecutor):
87
+ (implicit config: Config, s3Settings: S3Settings, ec: ExecutionContextExecutor, logger: Logger):
87
88
  ErrorOrS3FilesAndUpdates = Future {
88
- debug(nextMarker.fold
89
+ logger.debug(nextMarker.fold
89
90
  ("Querying S3 files")
90
91
  {m => s"Querying more S3 files (starting from $m)"}
91
92
  )
@@ -16,16 +16,16 @@ object Utils {
16
16
  lazy val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 }
17
17
  }
18
18
 
19
- object Logger {
19
+ class Logger(verboseOutput: Boolean, logMessage: (String) => Unit = println) {
20
20
  import Rainbow._
21
- def debug(msg: String) = println(s"[${"debg".cyan}] $msg")
22
- def info(msg: String) = println(s"[${"info".blue}] $msg")
23
- def fail(msg: String) = println(s"[${"fail".red}] $msg")
21
+ def debug(msg: String) = if (verboseOutput) logMessage(s"[${"debg".cyan}] $msg")
22
+ def info(msg: String) = logMessage(s"[${"info".blue}] $msg")
23
+ def fail(msg: String) = logMessage(s"[${"fail".red}] $msg")
24
24
 
25
- def info(report: SuccessReport) = println(s"[${"succ".green}] ${report.reportMessage}")
25
+ def info(report: SuccessReport) = logMessage(s"[${"succ".green}] ${report.reportMessage}")
26
26
  def info(report: FailureReport) = fail(report.reportMessage)
27
27
 
28
- def pending(msg: String) = println(s"[${"wait".yellow}] $msg")
28
+ def pending(msg: String) = logMessage(s"[${"wait".yellow}] $msg")
29
29
  }
30
30
 
31
31
  /**
@@ -6,7 +6,7 @@ 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._
9
+ import s3.website.Logger
10
10
  import scala.util.Failure
11
11
  import s3.website.model.Config.UnsafeYaml
12
12
  import scala.util.Success
@@ -17,7 +17,8 @@ case class Site(rootDirectory: String, config: Config) {
17
17
  }
18
18
 
19
19
  object Site {
20
- def loadSite(yamlConfigPath: String, siteRootDirectory: String): Either[ErrorReport, Site] = {
20
+ def loadSite(yamlConfigPath: String, siteRootDirectory: String)
21
+ (implicit logger: Logger): Either[ErrorReport, Site] = {
21
22
  val yamlObjectTry = for {
22
23
  yamlString <- Try(fromFile(new File(yamlConfigPath)).mkString)
23
24
  yamlWithErbEvaluated <- erbEval(yamlString, yamlConfigPath)
@@ -43,8 +44,8 @@ object Site {
43
44
  concurrency_level <- loadOptionalInt("concurrency_level").right
44
45
  redirects <- loadRedirects.right
45
46
  } yield {
46
- gzip_zopfli.foreach(_ => info("zopfli is not currently supported"))
47
- extensionless_mime_type.foreach(_ => info(
47
+ gzip_zopfli.foreach(_ => logger.info("zopfli is not currently supported"))
48
+ extensionless_mime_type.foreach(_ => logger.info(
48
49
  s"Ignoring the extensionless_mime_type setting in $yamlConfigPath. Counting on Apache Tika to infer correct mime types.")
49
50
  )
50
51
  Config(
@@ -1,12 +1,11 @@
1
1
  package s3
2
2
 
3
3
  import scala.concurrent.{ExecutionContextExecutor, Future}
4
- import s3.website.Logger._
5
4
  import scala.concurrent.duration.{TimeUnit, Duration}
6
5
  import s3.website.Utils._
7
6
  import s3.website.S3.{PushSuccessReport, PushFailureReport}
8
- import com.amazonaws.services.s3.model.AmazonS3Exception
9
7
  import com.amazonaws.AmazonServiceException
8
+ import s3.website.model.{Config, Site}
10
9
 
11
10
  package object website {
12
11
  trait Report {
@@ -28,16 +27,16 @@ package object website {
28
27
 
29
28
  def retry[L <: Report, R](attempt: Attempt)
30
29
  (createFailureReport: (Throwable) => L, retryAction: (Attempt) => Future[Either[L, R]])
31
- (implicit retrySettings: RetrySettings, ec: ExecutionContextExecutor):
30
+ (implicit retrySettings: RetrySettings, ec: ExecutionContextExecutor, logger: Logger):
32
31
  PartialFunction[Throwable, Future[Either[L, R]]] = {
33
32
  case error: Throwable if attempt == 6 || isIrrecoverable(error) =>
34
33
  val failureReport = createFailureReport(error)
35
- fail(failureReport.reportMessage)
34
+ logger.fail(failureReport.reportMessage)
36
35
  Future(Left(failureReport))
37
36
  case error: Throwable =>
38
37
  val failureReport = createFailureReport(error)
39
38
  val sleepDuration = Duration(fibs.drop(attempt + 1).head, retrySettings.retryTimeUnit)
40
- pending(s"${failureReport.reportMessage}. Trying again in $sleepDuration.")
39
+ logger.pending(s"${failureReport.reportMessage}. Trying again in $sleepDuration.")
41
40
  Thread.sleep(sleepDuration.toMillis)
42
41
  retryAction(attempt + 1)
43
42
  }
@@ -59,4 +58,6 @@ package object website {
59
58
  s"$count ${if (count > 1) plural else singular}"
60
59
  }
61
60
  }
61
+
62
+ implicit def site2Config(implicit site: Site): Config = site.config
62
63
  }
@@ -30,7 +30,7 @@ import scala.collection.mutable
30
30
  class S3WebsiteSpec extends Specification {
31
31
 
32
32
  "gzip: true" should {
33
- "update a gzipped S3 object if the contents has changed" in new EmptySite with MockAWS {
33
+ "update a gzipped S3 object if the contents has changed" in new EmptySite with VerboseLogger with MockAWS {
34
34
  config = "gzip: true"
35
35
  setLocalFileWithContent(("styles.css", "<h1>hi again</h1>"))
36
36
  setS3Files(S3File("styles.css", "1c5117e5839ad8fc00ce3c41296255a1" /* md5 of the gzip of the file contents */))
@@ -38,7 +38,7 @@ class S3WebsiteSpec extends Specification {
38
38
  sentPutObjectRequest.getKey must equalTo("styles.css")
39
39
  }
40
40
 
41
- "not update a gzipped S3 object if the contents has not changed" in new EmptySite with MockAWS {
41
+ "not update a gzipped S3 object if the contents has not changed" in new EmptySite with VerboseLogger with MockAWS {
42
42
  config = "gzip: true"
43
43
  setLocalFileWithContent(("styles.css", "<h1>hi</h1>"))
44
44
  setS3Files(S3File("styles.css", "1c5117e5839ad8fc00ce3c41296255a1" /* md5 of the gzip of the file contents */))
@@ -51,7 +51,7 @@ class S3WebsiteSpec extends Specification {
51
51
  gzip:
52
52
  - .xml
53
53
  """ should {
54
- "update a gzipped S3 object if the contents has changed" in new EmptySite with MockAWS {
54
+ "update a gzipped S3 object if the contents has changed" in new EmptySite with VerboseLogger with MockAWS {
55
55
  config = """
56
56
  |gzip:
57
57
  | - .xml
@@ -64,40 +64,40 @@ class S3WebsiteSpec extends Specification {
64
64
  }
65
65
 
66
66
  "push" should {
67
- "not upload a file if it has not changed" in new EmptySite with MockAWS {
67
+ "not upload a file if it has not changed" in new EmptySite with VerboseLogger with MockAWS {
68
68
  setLocalFileWithContent(("index.html", "<div>hello</div>"))
69
69
  setS3Files(S3File("index.html", md5Hex("<div>hello</div>")))
70
70
  Push.pushSite
71
71
  noUploadsOccurred must beTrue
72
72
  }
73
73
 
74
- "update a file if it has changed" in new EmptySite with MockAWS {
74
+ "update a file if it has changed" in new EmptySite with VerboseLogger with MockAWS {
75
75
  setLocalFileWithContent(("index.html", "<h1>old text</h1>"))
76
76
  setS3Files(S3File("index.html", md5Hex("<h1>new text</h1>")))
77
77
  Push.pushSite
78
78
  sentPutObjectRequest.getKey must equalTo("index.html")
79
79
  }
80
80
 
81
- "create a file if does not exist on S3" in new EmptySite with MockAWS {
81
+ "create a file if does not exist on S3" in new EmptySite with VerboseLogger with MockAWS {
82
82
  setLocalFile("index.html")
83
83
  Push.pushSite
84
84
  sentPutObjectRequest.getKey must equalTo("index.html")
85
85
  }
86
86
 
87
- "delete files that are on S3 but not on local file system" in new EmptySite with MockAWS {
87
+ "delete files that are on S3 but not on local file system" in new EmptySite with VerboseLogger with MockAWS {
88
88
  setS3Files(S3File("old.html", md5Hex("<h1>old text</h1>")))
89
89
  Push.pushSite
90
90
  sentDelete must equalTo("old.html")
91
91
  }
92
92
 
93
- "try again if the upload fails" in new EmptySite with MockAWS {
93
+ "try again if the upload fails" in new EmptySite with VerboseLogger with MockAWS {
94
94
  setLocalFile("index.html")
95
95
  uploadFailsAndThenSucceeds(howManyFailures = 5)
96
96
  Push.pushSite
97
97
  verify(amazonS3Client, times(6)).putObject(Matchers.any(classOf[PutObjectRequest]))
98
98
  }
99
99
 
100
- "not try again if the upload fails on because of invalid credentials" in new EmptySite with MockAWS {
100
+ "not try again if the upload fails on because of invalid credentials" in new EmptySite with VerboseLogger with MockAWS {
101
101
  setLocalFile("index.html")
102
102
  when(amazonS3Client.putObject(Matchers.any(classOf[PutObjectRequest]))).thenThrow {
103
103
  val e = new AmazonServiceException("your credentials are incorrect")
@@ -108,14 +108,14 @@ class S3WebsiteSpec extends Specification {
108
108
  verify(amazonS3Client, times(1)).putObject(Matchers.any(classOf[PutObjectRequest]))
109
109
  }
110
110
 
111
- "try again if the delete fails" in new EmptySite with MockAWS {
111
+ "try again if the delete fails" in new EmptySite with VerboseLogger with MockAWS {
112
112
  setS3Files(S3File("old.html", md5Hex("<h1>old text</h1>")))
113
113
  deleteFailsAndThenSucceeds(howManyFailures = 5)
114
114
  Push.pushSite
115
115
  verify(amazonS3Client, times(6)).deleteObject(Matchers.anyString(), Matchers.anyString())
116
116
  }
117
117
 
118
- "try again if the object listing fails" in new EmptySite with MockAWS {
118
+ "try again if the object listing fails" in new EmptySite with VerboseLogger with MockAWS {
119
119
  setS3Files(S3File("old.html", md5Hex("<h1>old text</h1>")))
120
120
  objectListingFailsAndThenSucceeds(howManyFailures = 5)
121
121
  Push.pushSite
@@ -124,7 +124,7 @@ class S3WebsiteSpec extends Specification {
124
124
  }
125
125
 
126
126
  "push with CloudFront" should {
127
- "invalidate the updated CloudFront items" in new EmptySite with MockAWS {
127
+ "invalidate the updated CloudFront items" in new EmptySite with VerboseLogger with MockAWS {
128
128
  config = "cloudfront_distribution_id: EGM1J2JJX9Z"
129
129
  setLocalFiles("css/test.css", "articles/index.html")
130
130
  setOutdatedS3Keys("css/test.css", "articles/index.html")
@@ -132,14 +132,14 @@ class S3WebsiteSpec extends Specification {
132
132
  sentInvalidationRequest.getInvalidationBatch.getPaths.getItems.toSeq.sorted must equalTo(("/css/test.css" :: "/articles/index.html" :: Nil).sorted)
133
133
  }
134
134
 
135
- "not send CloudFront invalidation requests on new objects" in new EmptySite with MockAWS {
135
+ "not send CloudFront invalidation requests on new objects" in new EmptySite with VerboseLogger with MockAWS {
136
136
  config = "cloudfront_distribution_id: EGM1J2JJX9Z"
137
137
  setLocalFile("newfile.js")
138
138
  Push.pushSite
139
139
  noInvalidationsOccurred must beTrue
140
140
  }
141
141
 
142
- "not send CloudFront invalidation requests on redirect objects" in new EmptySite with MockAWS {
142
+ "not send CloudFront invalidation requests on redirect objects" in new EmptySite with VerboseLogger with MockAWS {
143
143
  config = """
144
144
  |cloudfront_distribution_id: EGM1J2JJX9Z
145
145
  |redirects:
@@ -149,7 +149,7 @@ class S3WebsiteSpec extends Specification {
149
149
  noInvalidationsOccurred must beTrue
150
150
  }
151
151
 
152
- "retry CloudFront responds with TooManyInvalidationsInProgressException" in new EmptySite with MockAWS {
152
+ "retry CloudFront responds with TooManyInvalidationsInProgressException" in new EmptySite with VerboseLogger with MockAWS {
153
153
  setTooManyInvalidationsInProgress(4)
154
154
  config = "cloudfront_distribution_id: EGM1J2JJX9Z"
155
155
  setLocalFile("test.css")
@@ -158,7 +158,7 @@ class S3WebsiteSpec extends Specification {
158
158
  sentInvalidationRequests.length must equalTo(4)
159
159
  }
160
160
 
161
- "retry if CloudFront is temporarily unreachable" in new EmptySite with MockAWS {
161
+ "retry if CloudFront is temporarily unreachable" in new EmptySite with VerboseLogger with MockAWS {
162
162
  invalidationsFailAndThenSucceed(5)
163
163
  config = "cloudfront_distribution_id: EGM1J2JJX9Z"
164
164
  setLocalFile("test.css")
@@ -167,7 +167,7 @@ class S3WebsiteSpec extends Specification {
167
167
  sentInvalidationRequests.length must equalTo(6)
168
168
  }
169
169
 
170
- "encode unsafe characters in the keys" in new EmptySite with MockAWS {
170
+ "encode unsafe characters in the keys" in new EmptySite with VerboseLogger with MockAWS {
171
171
  config = "cloudfront_distribution_id: EGM1J2JJX9Z"
172
172
  setLocalFile("articles/arnold's file.html")
173
173
  setOutdatedS3Keys("articles/arnold's file.html")
@@ -179,7 +179,7 @@ class S3WebsiteSpec extends Specification {
179
179
  * Because CloudFront supports Default Root Objects (http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DefaultRootObject.html),
180
180
  * we have to guess
181
181
  */
182
- "invalidate the root object '/' if a top-level object is updated or deleted" in new EmptySite with MockAWS {
182
+ "invalidate the root object '/' if a top-level object is updated or deleted" in new EmptySite with VerboseLogger with MockAWS {
183
183
  config = "cloudfront_distribution_id: EGM1J2JJX9Z"
184
184
  setLocalFile("maybe-index.html")
185
185
  setOutdatedS3Keys("maybe-index.html")
@@ -189,7 +189,7 @@ class S3WebsiteSpec extends Specification {
189
189
  }
190
190
 
191
191
  "cloudfront_invalidate_root: true" should {
192
- "convert CloudFront invalidation paths with the '/index.html' suffix into '/'" in new EmptySite with MockAWS {
192
+ "convert CloudFront invalidation paths with the '/index.html' suffix into '/'" in new EmptySite with VerboseLogger with MockAWS {
193
193
  config = """
194
194
  |cloudfront_distribution_id: EGM1J2JJX9Z
195
195
  |cloudfront_invalidate_root: true
@@ -202,7 +202,7 @@ class S3WebsiteSpec extends Specification {
202
202
  }
203
203
 
204
204
  "a site with over 1000 items" should {
205
- "split the CloudFront invalidation requests into batches of 1000 items" in new EmptySite with MockAWS {
205
+ "split the CloudFront invalidation requests into batches of 1000 items" in new EmptySite with VerboseLogger with MockAWS {
206
206
  val files = (1 to 1002).map { i => s"lots-of-files/file-$i"}
207
207
  config = "cloudfront_distribution_id: EGM1J2JJX9Z"
208
208
  setLocalFiles(files:_*)
@@ -215,18 +215,18 @@ class S3WebsiteSpec extends Specification {
215
215
  }
216
216
 
217
217
  "push exit status" should {
218
- "be 0 all uploads succeed" in new EmptySite with MockAWS {
218
+ "be 0 all uploads succeed" in new EmptySite with VerboseLogger with MockAWS {
219
219
  setLocalFiles("file.txt")
220
220
  Push.pushSite must equalTo(0)
221
221
  }
222
222
 
223
- "be 1 if any of the uploads fails" in new EmptySite with MockAWS {
223
+ "be 1 if any of the uploads fails" in new EmptySite with VerboseLogger with MockAWS {
224
224
  setLocalFiles("file.txt")
225
225
  when(amazonS3Client.putObject(Matchers.any(classOf[PutObjectRequest]))).thenThrow(new AmazonServiceException("AWS failed"))
226
226
  Push.pushSite must equalTo(1)
227
227
  }
228
228
 
229
- "be 1 if any of the redirects fails" in new EmptySite with MockAWS {
229
+ "be 1 if any of the redirects fails" in new EmptySite with VerboseLogger with MockAWS {
230
230
  config = """
231
231
  |redirects:
232
232
  | index.php: /index.html
@@ -235,14 +235,14 @@ class S3WebsiteSpec extends Specification {
235
235
  Push.pushSite must equalTo(1)
236
236
  }
237
237
 
238
- "be 0 if CloudFront invalidations and uploads succeed"in new EmptySite with MockAWS {
238
+ "be 0 if CloudFront invalidations and uploads succeed"in new EmptySite with VerboseLogger with MockAWS {
239
239
  config = "cloudfront_distribution_id: EGM1J2JJX9Z"
240
240
  setLocalFile("test.css")
241
241
  setOutdatedS3Keys("test.css")
242
242
  Push.pushSite must equalTo(0)
243
243
  }
244
244
 
245
- "be 1 if CloudFront is unreachable or broken"in new EmptySite with MockAWS {
245
+ "be 1 if CloudFront is unreachable or broken"in new EmptySite with VerboseLogger with MockAWS {
246
246
  setCloudFrontAsInternallyBroken()
247
247
  config = "cloudfront_distribution_id: EGM1J2JJX9Z"
248
248
  setLocalFile("test.css")
@@ -250,19 +250,19 @@ class S3WebsiteSpec extends Specification {
250
250
  Push.pushSite must equalTo(1)
251
251
  }
252
252
 
253
- "be 0 if upload retry succeeds" in new EmptySite with MockAWS {
253
+ "be 0 if upload retry succeeds" in new EmptySite with VerboseLogger with MockAWS {
254
254
  setLocalFile("index.html")
255
255
  uploadFailsAndThenSucceeds(howManyFailures = 1)
256
256
  Push.pushSite must equalTo(0)
257
257
  }
258
258
 
259
- "be 1 if delete retry fails" in new EmptySite with MockAWS {
259
+ "be 1 if delete retry fails" in new EmptySite with VerboseLogger with MockAWS {
260
260
  setLocalFile("index.html")
261
261
  uploadFailsAndThenSucceeds(howManyFailures = 6)
262
262
  Push.pushSite must equalTo(1)
263
263
  }
264
264
 
265
- "be 1 if an object listing fails" in new EmptySite with MockAWS {
265
+ "be 1 if an object listing fails" in new EmptySite with VerboseLogger with MockAWS {
266
266
  setS3Files(S3File("old.html", md5Hex("<h1>old text</h1>")))
267
267
  objectListingFailsAndThenSucceeds(howManyFailures = 6)
268
268
  Push.pushSite must equalTo(1)
@@ -270,7 +270,7 @@ class S3WebsiteSpec extends Specification {
270
270
  }
271
271
 
272
272
  "s3_website.yml file" should {
273
- "never be uploaded" in new EmptySite with MockAWS {
273
+ "never be uploaded" in new EmptySite with VerboseLogger with MockAWS {
274
274
  setLocalFile("s3_website.yml")
275
275
  Push.pushSite
276
276
  noUploadsOccurred must beTrue
@@ -278,7 +278,7 @@ class S3WebsiteSpec extends Specification {
278
278
  }
279
279
 
280
280
  "exclude_from_upload: string" should {
281
- "result in matching files not being uploaded" in new EmptySite with MockAWS {
281
+ "result in matching files not being uploaded" in new EmptySite with VerboseLogger with MockAWS {
282
282
  config = "exclude_from_upload: .DS_.*?"
283
283
  setLocalFile(".DS_Store")
284
284
  Push.pushSite
@@ -291,7 +291,7 @@ class S3WebsiteSpec extends Specification {
291
291
  - regex
292
292
  - another_exclusion
293
293
  """ should {
294
- "result in matching files not being uploaded" in new EmptySite with MockAWS {
294
+ "result in matching files not being uploaded" in new EmptySite with VerboseLogger with MockAWS {
295
295
  config = """
296
296
  |exclude_from_upload:
297
297
  | - .DS_.*?
@@ -304,7 +304,7 @@ class S3WebsiteSpec extends Specification {
304
304
  }
305
305
 
306
306
  "ignore_on_server: value" should {
307
- "not delete the S3 objects that match the ignore value" in new EmptySite with MockAWS {
307
+ "not delete the S3 objects that match the ignore value" in new EmptySite with VerboseLogger with MockAWS {
308
308
  config = "ignore_on_server: logs"
309
309
  setS3Files(S3File("logs/log.txt", ""))
310
310
  Push.pushSite
@@ -317,7 +317,7 @@ class S3WebsiteSpec extends Specification {
317
317
  - regex
318
318
  - another_ignore
319
319
  """ should {
320
- "not delete the S3 objects that match the ignore value" in new EmptySite with MockAWS {
320
+ "not delete the S3 objects that match the ignore value" in new EmptySite with VerboseLogger with MockAWS {
321
321
  config = """
322
322
  |ignore_on_server:
323
323
  | - .*txt
@@ -329,14 +329,14 @@ class S3WebsiteSpec extends Specification {
329
329
  }
330
330
 
331
331
  "max-age in config" can {
332
- "be applied to all files" in new EmptySite with MockAWS {
332
+ "be applied to all files" in new EmptySite with VerboseLogger with MockAWS {
333
333
  config = "max_age: 60"
334
334
  setLocalFile("index.html")
335
335
  Push.pushSite
336
336
  sentPutObjectRequest.getMetadata.getCacheControl must equalTo("max-age=60")
337
337
  }
338
338
 
339
- "be applied to files that match the glob" in new EmptySite with MockAWS {
339
+ "be applied to files that match the glob" in new EmptySite with VerboseLogger with MockAWS {
340
340
  config = """
341
341
  |max_age:
342
342
  | "*.html": 90
@@ -346,7 +346,7 @@ class S3WebsiteSpec extends Specification {
346
346
  sentPutObjectRequest.getMetadata.getCacheControl must equalTo("max-age=90")
347
347
  }
348
348
 
349
- "be applied to directories that match the glob" in new EmptySite with MockAWS {
349
+ "be applied to directories that match the glob" in new EmptySite with VerboseLogger with MockAWS {
350
350
  config = """
351
351
  |max_age:
352
352
  | "assets/**/*.js": 90
@@ -356,7 +356,7 @@ class S3WebsiteSpec extends Specification {
356
356
  sentPutObjectRequest.getMetadata.getCacheControl must equalTo("max-age=90")
357
357
  }
358
358
 
359
- "not be applied if the glob doesn't match" in new EmptySite with MockAWS {
359
+ "not be applied if the glob doesn't match" in new EmptySite with VerboseLogger with MockAWS {
360
360
  config = """
361
361
  |max_age:
362
362
  | "*.js": 90
@@ -366,7 +366,7 @@ class S3WebsiteSpec extends Specification {
366
366
  sentPutObjectRequest.getMetadata.getCacheControl must beNull
367
367
  }
368
368
 
369
- "be used to disable caching" in new EmptySite with MockAWS {
369
+ "be used to disable caching" in new EmptySite with VerboseLogger with MockAWS {
370
370
  config = "max_age: 0"
371
371
  setLocalFile("index.html")
372
372
  Push.pushSite
@@ -375,7 +375,7 @@ class S3WebsiteSpec extends Specification {
375
375
  }
376
376
 
377
377
  "max-age in config" should {
378
- "respect the more specific glob" in new EmptySite with MockAWS {
378
+ "respect the more specific glob" in new EmptySite with VerboseLogger with MockAWS {
379
379
  config = """
380
380
  |max_age:
381
381
  | "assets/*": 150
@@ -389,7 +389,7 @@ class S3WebsiteSpec extends Specification {
389
389
  }
390
390
 
391
391
  "s3_reduced_redundancy: true in config" should {
392
- "result in uploads being marked with reduced redundancy" in new EmptySite with MockAWS {
392
+ "result in uploads being marked with reduced redundancy" in new EmptySite with VerboseLogger with MockAWS {
393
393
  config = "s3_reduced_redundancy: true"
394
394
  setLocalFile("file.exe")
395
395
  Push.pushSite
@@ -398,7 +398,7 @@ class S3WebsiteSpec extends Specification {
398
398
  }
399
399
 
400
400
  "s3_reduced_redundancy: false in config" should {
401
- "result in uploads being marked with the default storage class" in new EmptySite with MockAWS {
401
+ "result in uploads being marked with the default storage class" in new EmptySite with VerboseLogger with MockAWS {
402
402
  config = "s3_reduced_redundancy: false"
403
403
  setLocalFile("file.exe")
404
404
  Push.pushSite
@@ -407,7 +407,7 @@ class S3WebsiteSpec extends Specification {
407
407
  }
408
408
 
409
409
  "redirect in config" should {
410
- "result in a redirect instruction that is sent to AWS" in new EmptySite with MockAWS {
410
+ "result in a redirect instruction that is sent to AWS" in new EmptySite with VerboseLogger with MockAWS {
411
411
  config = """
412
412
  |redirects:
413
413
  | index.php: /index.html
@@ -416,7 +416,7 @@ class S3WebsiteSpec extends Specification {
416
416
  sentPutObjectRequest.getRedirectLocation must equalTo("/index.html")
417
417
  }
418
418
 
419
- "result in max-age=0 Cache-Control header on the object" in new EmptySite with MockAWS {
419
+ "result in max-age=0 Cache-Control header on the object" in new EmptySite with VerboseLogger with MockAWS {
420
420
  config = """
421
421
  |redirects:
422
422
  | index.php: /index.html
@@ -427,7 +427,7 @@ class S3WebsiteSpec extends Specification {
427
427
  }
428
428
 
429
429
  "redirect in config and an object on the S3 bucket" should {
430
- "not result in the S3 object being deleted" in new EmptySite with MockAWS {
430
+ "not result in the S3 object being deleted" in new EmptySite with VerboseLogger with MockAWS {
431
431
  config = """
432
432
  |redirects:
433
433
  | index.php: /index.html
@@ -440,7 +440,7 @@ class S3WebsiteSpec extends Specification {
440
440
  }
441
441
 
442
442
  "dotfiles" should {
443
- "be included in the pushed files" in new EmptySite with MockAWS {
443
+ "be included in the pushed files" in new EmptySite with VerboseLogger with MockAWS {
444
444
  setLocalFile(".vimrc")
445
445
  Push.pushSite
446
446
  sentPutObjectRequest.getKey must equalTo(".vimrc")
@@ -448,25 +448,25 @@ class S3WebsiteSpec extends Specification {
448
448
  }
449
449
 
450
450
  "content type inference" should {
451
- "add charset=utf-8 to all html documents" in new EmptySite with MockAWS {
451
+ "add charset=utf-8 to all html documents" in new EmptySite with VerboseLogger with MockAWS {
452
452
  setLocalFile("index.html")
453
453
  Push.pushSite
454
454
  sentPutObjectRequest.getMetadata.getContentType must equalTo("text/html; charset=utf-8")
455
455
  }
456
456
 
457
- "add charset=utf-8 to all text documents" in new EmptySite with MockAWS {
457
+ "add charset=utf-8 to all text documents" in new EmptySite with VerboseLogger with MockAWS {
458
458
  setLocalFile("index.txt")
459
459
  Push.pushSite
460
460
  sentPutObjectRequest.getMetadata.getContentType must equalTo("text/plain; charset=utf-8")
461
461
  }
462
462
 
463
- "add charset=utf-8 to all json documents" in new EmptySite with MockAWS {
463
+ "add charset=utf-8 to all json documents" in new EmptySite with VerboseLogger with MockAWS {
464
464
  setLocalFile("data.json")
465
465
  Push.pushSite
466
466
  sentPutObjectRequest.getMetadata.getContentType must equalTo("application/json; charset=utf-8")
467
467
  }
468
468
 
469
- "resolve the content type from file contents" in new EmptySite with MockAWS {
469
+ "resolve the content type from file contents" in new EmptySite with VerboseLogger with MockAWS {
470
470
  setLocalFileWithContent(("index", "<html><body><h1>hi</h1></body></html>"))
471
471
  Push.pushSite
472
472
  sentPutObjectRequest.getMetadata.getContentType must equalTo("text/html; charset=utf-8")
@@ -474,7 +474,7 @@ class S3WebsiteSpec extends Specification {
474
474
  }
475
475
 
476
476
  "ERB in config file" should {
477
- "be evaluated" in new EmptySite with MockAWS {
477
+ "be evaluated" in new EmptySite with VerboseLogger with MockAWS {
478
478
  config = """
479
479
  |redirects:
480
480
  |<%= ('a'..'f').to_a.map do |t| ' '+t+ ': /'+t+'.html' end.join('\n')%>
@@ -484,8 +484,37 @@ class S3WebsiteSpec extends Specification {
484
484
  sentPutObjectRequests.forall(_.getRedirectLocation != null) must beTrue
485
485
  }
486
486
  }
487
+
488
+ "logging" should {
489
+ "print the debug messages when --verbose is defined" in new EmptySite with VerboseLogger with MockAWS {
490
+ Push.pushSite
491
+ logEntries must contain("[debg] Querying S3 files")
492
+ }
493
+
494
+ "not print the debug messages by default" in new EmptySite with NonVerboseLogger with MockAWS {
495
+ Push.pushSite
496
+ logEntries.forall(_.contains("[debg]")) must beFalse
497
+ }
498
+ }
487
499
 
488
500
  trait MockAWS extends MockS3 with MockCloudFront with Scope
501
+
502
+ trait VerboseLogger extends LogCapturer {
503
+ implicit val logger: Logger = new Logger(verboseOutput = true, logMessage = captureAndPrint)
504
+ }
505
+
506
+ trait NonVerboseLogger extends LogCapturer {
507
+ implicit val logger: Logger = new Logger(verboseOutput = false, logMessage = captureAndPrint)
508
+ }
509
+
510
+ trait LogCapturer {
511
+ val logEntries: mutable.Buffer[String] = mutable.Buffer()
512
+
513
+ def captureAndPrint(msg: String) {
514
+ logEntries += msg.replaceAll("\u001B\\[[;\\d]*m", "") // Remove ANSI coloring
515
+ println(msg)
516
+ }
517
+ }
489
518
 
490
519
  trait MockCloudFront extends MockAWSHelper {
491
520
  val amazonCloudFrontClient = mock(classOf[AmazonCloudFront])
@@ -581,7 +610,7 @@ class S3WebsiteSpec extends Specification {
581
610
  .listObjects(Matchers.any(classOf[ListObjectsRequest]))
582
611
  }
583
612
 
584
- def asSeenByS3Client(upload: Upload)(implicit config: Config): PutObjectRequest = {
613
+ def asSeenByS3Client(upload: Upload)(implicit config: Config, logger: Logger): PutObjectRequest = {
585
614
  Await.ready(s3.upload(upload withUploadType NewFile), Duration("1 s"))
586
615
  val req = ArgumentCaptor.forClass(classOf[PutObjectRequest])
587
616
  verify(amazonS3Client).putObject(req.capture())
@@ -654,7 +683,8 @@ class S3WebsiteSpec extends Specification {
654
683
  |s3_bucket: bucket
655
684
  """.stripMargin
656
685
 
657
- implicit def site2: Site = siteWithFilesAndContent(config, localFilesWithContent)
686
+ implicit lazy val testSite: Site = siteWithFilesAndContent(config, localFilesWithContent)
687
+ implicit def logger: Logger
658
688
 
659
689
  def buildSite(
660
690
  config: String = "",
@@ -672,7 +702,7 @@ class S3WebsiteSpec extends Specification {
672
702
  |$config
673
703
  """.stripMargin
674
704
  )
675
- val errorOrSite: Either[ErrorReport, Site] = Site.loadSite(configFile.getAbsolutePath, siteDir.getAbsolutePath)
705
+ val errorOrSite: Either[ErrorReport, Site] = Site.loadSite(configFile.getAbsolutePath, siteDir.getAbsolutePath)(logger)
676
706
  errorOrSite.left.foreach (error => throw new RuntimeException(error.reportMessage))
677
707
  errorOrSite.right.get
678
708
  }
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.26
4
+ version: 0.0.27
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 00:00:00.000000000 Z
11
+ date: 2014-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -115,7 +115,6 @@ files:
115
115
  - sbt
116
116
  - src/main/scala/s3/website/CloudFront.scala
117
117
  - src/main/scala/s3/website/Diff.scala
118
- - src/main/scala/s3/website/Implicits.scala
119
118
  - src/main/scala/s3/website/Push.scala
120
119
  - src/main/scala/s3/website/Ruby.scala
121
120
  - src/main/scala/s3/website/S3.scala
@@ -1,7 +0,0 @@
1
- package s3.website
2
-
3
- import s3.website.model.{Site, Config}
4
-
5
- object Implicits {
6
- implicit def site2Config(implicit site: Site): Config = site.config
7
- }