Class: Match::Storage::S3Storage

Inherits:
Interface show all
Defined in:
match/lib/match/storage/s3_storage.rb

Overview

Store the code signing identities on AWS S3

Constant Summary

Constants inherited from Interface

Interface::MATCH_VERSION_FILE_NAME

Instance Attribute Summary collapse

Attributes inherited from Interface

#working_directory

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Interface

#clear_changes, #configure, #save_changes!

Constructor Details

#initialize(s3_region: nil, s3_access_key: nil, s3_secret_access_key: nil, s3_bucket: nil, readonly: nil, username: nil, team_id: nil, team_name: nil) ⇒ S3Storage

Returns a new instance of S3Storage.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'match/lib/match/storage/s3_storage.rb', line 47

def initialize(s3_region: nil,
               s3_access_key: nil,
               s3_secret_access_key: nil,
               s3_bucket: nil,
               readonly: nil,
               username: nil,
               team_id: nil,
               team_name: nil)
  @s3_bucket = s3_bucket
  @s3_region = s3_region
  @s3_client = Fastlane::Helper::S3ClientHelper.new(access_key: s3_access_key, secret_access_key: s3_secret_access_key, region: s3_region)
  @readonly = readonly
  @username = username
  @team_id = team_id
  @team_name = team_name
end

Instance Attribute Details

#readonlyObject (readonly)

Returns the value of attribute readonly.



17
18
19
# File 'match/lib/match/storage/s3_storage.rb', line 17

def readonly
  @readonly
end

#s3_bucketObject (readonly)

Returns the value of attribute s3_bucket.



14
15
16
# File 'match/lib/match/storage/s3_storage.rb', line 14

def s3_bucket
  @s3_bucket
end

#s3_clientObject (readonly)

Returns the value of attribute s3_client.



16
17
18
# File 'match/lib/match/storage/s3_storage.rb', line 16

def s3_client
  @s3_client
end

#s3_regionObject (readonly)

Returns the value of attribute s3_region.



15
16
17
# File 'match/lib/match/storage/s3_storage.rb', line 15

def s3_region
  @s3_region
end

#team_idObject (readonly)

Returns the value of attribute team_id.



19
20
21
# File 'match/lib/match/storage/s3_storage.rb', line 19

def team_id
  @team_id
end

#team_nameObject (readonly)

Returns the value of attribute team_name.



20
21
22
# File 'match/lib/match/storage/s3_storage.rb', line 20

def team_name
  @team_name
end

#usernameObject (readonly)

Returns the value of attribute username.



18
19
20
# File 'match/lib/match/storage/s3_storage.rb', line 18

def username
  @username
end

Class Method Details

.configure(params) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'match/lib/match/storage/s3_storage.rb', line 22

def self.configure(params)
  s3_region = params[:s3_region]
  s3_access_key = params[:s3_access_key]
  s3_secret_access_key = params[:s3_secret_access_key]
  s3_bucket = params[:s3_bucket]

  if params[:git_url].to_s.length > 0
    UI.important("Looks like you still define a `git_url` somewhere, even though")
    UI.important("you use S3 Storage. You can remove the `git_url`")
    UI.important("from your Matchfile and Fastfile")
    UI.message("The above is just a warning, fastlane will continue as usual now...")
  end

  return self.new(
    s3_region: s3_region,
    s3_access_key: s3_access_key,
    s3_secret_access_key: s3_secret_access_key,
    s3_bucket: s3_bucket,
    readonly: params[:readonly],
    username: params[:username],
    team_id: params[:team_id],
    team_name: params[:team_name]
  )
end

Instance Method Details

#delete_files(files_to_delete: [], custom_message: nil) ⇒ Object



131
132
133
134
135
136
# File 'match/lib/match/storage/s3_storage.rb', line 131

def delete_files(files_to_delete: [], custom_message: nil)
  files_to_delete.each do |file_name|
    target_path = sanitize_file_name(file_name)
    s3_client.delete_file(s3_bucket, target_path)
  end
end

#downloadObject

Call this method for the initial clone/download of the user’s certificates & profiles As part of this method, the ‘self.working_directory` attribute will be set



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'match/lib/match/storage/s3_storage.rb', line 84

def download
  # Check if we already have a functional working_directory
  return if @working_directory && Dir.exist?(@working_directory)

  # No existing working directory, creating a new one now
  self.working_directory = Dir.mktmpdir

  s3_client.find_bucket!(s3_bucket).objects.each do |object|
    file_path = object.key # :team_id/path/to/file
    download_path = File.join(self.working_directory, file_path)

    FileUtils.mkdir_p(File.expand_path("..", download_path))
    UI.verbose("Downloading file from S3 '#{file_path}' on bucket #{self.s3_bucket}")

    object.download_file(download_path)
  end
  UI.verbose("Successfully downloaded files from S3 to #{self.working_directory}")
end

#generate_matchfile_content(template: nil) ⇒ Object

Implement this for the ‘fastlane match init` command This method must return the content of the Matchfile that should be generated



149
150
151
# File 'match/lib/match/storage/s3_storage.rb', line 149

def generate_matchfile_content(template: nil)
  return "s3_bucket(\"#{self.s3_bucket}\")"
end

#human_readable_descriptionObject

Returns a short string describing + identifing the current storage backend. This will be printed when nuking a storage



105
106
107
# File 'match/lib/match/storage/s3_storage.rb', line 105

def human_readable_description
  return "S3 Bucket [#{s3_bucket}] on region #{s3_region}"
end

#list_files(file_name: "", file_ext: "") ⇒ Object



142
143
144
# File 'match/lib/match/storage/s3_storage.rb', line 142

def list_files(file_name: "", file_ext: "")
  Dir[File.join(working_directory, self.team_id, "**", file_name, "*.#{file_ext}")]
end

#prefixed_working_directoryObject

To make debugging easier, we have a custom exception here



65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'match/lib/match/storage/s3_storage.rb', line 65

def prefixed_working_directory
  # We fall back to "*", which means certificates and profiles
  # from all teams that use this bucket would be installed. This is not ideal, but
  # unless the user provides a `team_id`, we can't know which one to use
  # This only happens if `readonly` is activated, and no `team_id` was provided
  @_folder_prefix ||= currently_used_team_id
  if @_folder_prefix.nil?
    # We use a `@_folder_prefix` variable, to keep state between multiple calls of this
    # method, as the value won't change. This way the warning is only printed once
    UI.important("Looks like you run `match` in `readonly` mode, and didn't provide a `team_id`. This will still work, however it is recommended to provide a `team_id` in your Appfile or Matchfile")
    @_folder_prefix = "*"
  end
  return File.join(working_directory, @_folder_prefix)
end

#skip_docsObject



138
139
140
# File 'match/lib/match/storage/s3_storage.rb', line 138

def skip_docs
  false
end

#upload_files(files_to_upload: [], custom_message: nil) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'match/lib/match/storage/s3_storage.rb', line 109

def upload_files(files_to_upload: [], custom_message: nil)
  # `files_to_upload` is an array of files that need to be uploaded to S3
  # Those doesn't mean they're new, it might just be they're changed
  # Either way, we'll upload them using the same technique

  files_to_upload.each do |file_name|
    # Go from
    #   "/var/folders/px/bz2kts9n69g8crgv4jpjh6b40000gn/T/d20181026-96528-1av4gge/profiles/development/Development_me.mobileprovision"
    # to
    #   "profiles/development/Development_me.mobileprovision"
    #

    target_path = sanitize_file_name(file_name)
    UI.verbose("Uploading '#{target_path}' to S3 Storage...")

    body = File.read(file_name)
    acl = 'private'
    s3_url = s3_client.upload_file(s3_bucket, target_path, body, acl)
    UI.verbose("Uploaded '#{s3_url}' to S3 Storage.")
  end
end