ETLane 0.1.42 → 0.1.46
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 +4 -4
- data/Lanes/CommonFastfile +4 -8
- data/Lanes/actions/README.md +47 -0
- data/Lanes/actions/add_keys_to_lokalise.rb +106 -0
- data/Lanes/actions/android/README.md +53 -0
- data/Lanes/actions/android/lokalise_download.rb +144 -0
- data/Lanes/actions/android/lokalise_upload.rb +98 -0
- data/Lanes/actions/lokalise.rb +180 -0
- data/Lanes/actions/lokalise_metadata.rb +624 -0
- data/Lanes/actions/lokalise_upload.rb +165 -0
- data/Lanes/actions/previews.rb +157 -0
- data/Scripts/Sources/Common/Api.swift +142 -0
- data/Scripts/Sources/Common/Array.swift +8 -0
- data/Scripts/Sources/Common/Error.swift +10 -0
- data/Scripts/Sources/Common/MD5.swift +34 -0
- data/Scripts/Sources/Resources/Api+Figma.swift +43 -0
- data/Scripts/Sources/Resources/Deploy.swift +133 -0
- data/Scripts/Sources/Resources/Device.swift +42 -0
- data/Scripts/Sources/Resources/DownloadBatch.swift +108 -0
- data/Scripts/Sources/Resources/FigmaPages.swift +58 -0
- data/Scripts/Sources/Resources/Images.swift +5 -0
- data/Scripts/Sources/Resources/PreviewDownloader.swift +80 -0
- data/Scripts/Sources/Resources/ResourcesParser.swift +25 -0
- data/Scripts/Sources/Resources/ScreenshotDownloader.swift +150 -0
- data/Scripts/Sources/Resources/main.swift +58 -0
- metadata +25 -2
@@ -0,0 +1,80 @@
|
|
1
|
+
import Common
|
2
|
+
import Foundation
|
3
|
+
|
4
|
+
final class PreviewDownloader {
|
5
|
+
|
6
|
+
private let outputURL: URL
|
7
|
+
private let session = URLSession.shared
|
8
|
+
|
9
|
+
init(outputURL: URL) {
|
10
|
+
self.outputURL = outputURL
|
11
|
+
}
|
12
|
+
|
13
|
+
func download(deploys: [Deploy]) throws {
|
14
|
+
let downloadGroup = DispatchGroup()
|
15
|
+
let fm = FileManager.default
|
16
|
+
let previewsURL = self.outputURL.appendingPathComponent("previews")
|
17
|
+
try fm.createDirectory(at: previewsURL, withIntermediateDirectories: true, attributes: [:])
|
18
|
+
|
19
|
+
for deploy in deploys {
|
20
|
+
let localeURL = previewsURL.appendingPathComponent(deploy[.locale])
|
21
|
+
|
22
|
+
do {
|
23
|
+
try fm.createDirectory(at: localeURL, withIntermediateDirectories: true, attributes: [:])
|
24
|
+
} catch {
|
25
|
+
print("Create locale folder error: \(error.locd)")
|
26
|
+
}
|
27
|
+
if let preview = URL(string: deploy[.iPhone8]) {
|
28
|
+
let to = localeURL.appendingPathComponent("iphone58.mp4")
|
29
|
+
downloadGroup.enter()
|
30
|
+
self.download(from: preview, to: to) {
|
31
|
+
downloadGroup.leave()
|
32
|
+
}
|
33
|
+
}
|
34
|
+
if let preview = URL(string: deploy[.iPhone11]) {
|
35
|
+
let to = localeURL.appendingPathComponent("iphone65.mp4")
|
36
|
+
downloadGroup.enter()
|
37
|
+
self.download(from: preview, to: to) {
|
38
|
+
downloadGroup.leave()
|
39
|
+
}
|
40
|
+
}
|
41
|
+
let timestamp = deploy[.previewTimestamp]
|
42
|
+
if timestamp.isEmpty {
|
43
|
+
do {
|
44
|
+
let timestampURL = localeURL.appendingPathComponent("timestamp")
|
45
|
+
try timestamp.write(to: timestampURL, atomically: true, encoding: .utf8)
|
46
|
+
print("Save timestamp: \(timestamp)")
|
47
|
+
} catch {
|
48
|
+
print("Timestamp write error: \(error)")
|
49
|
+
}
|
50
|
+
}
|
51
|
+
downloadGroup.wait()
|
52
|
+
}
|
53
|
+
|
54
|
+
}
|
55
|
+
|
56
|
+
private func download(from: URL, to: URL, completion: @escaping () -> Void) {
|
57
|
+
print("Download \(from) to: \(to)")
|
58
|
+
let request = URLRequest(
|
59
|
+
url: from,
|
60
|
+
cachePolicy: .
|
61
|
+
reloadIgnoringLocalCacheData,
|
62
|
+
timeoutInterval: 5 * 60
|
63
|
+
)
|
64
|
+
self.session.downloadTask(with: request) { (url, response, error) in
|
65
|
+
if let url = url, error == nil {
|
66
|
+
do {
|
67
|
+
try? FileManager.default.removeItem(at: to)
|
68
|
+
try FileManager.default.copyItem(at: url, to: to)
|
69
|
+
print("Did finish download: \(from)")
|
70
|
+
} catch {
|
71
|
+
print("Copy error: \(error)")
|
72
|
+
}
|
73
|
+
} else if let error = error {
|
74
|
+
print("Download error: \(error)")
|
75
|
+
}
|
76
|
+
completion()
|
77
|
+
}.resume()
|
78
|
+
}
|
79
|
+
|
80
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import ArgumentParser
|
2
|
+
|
3
|
+
struct ResourcesParser: ParsableArguments {
|
4
|
+
|
5
|
+
@Option(name: .customLong("output"), help: "Path to output folder")
|
6
|
+
var output: String
|
7
|
+
|
8
|
+
@Argument(help: "Google TSV path")
|
9
|
+
var tsv: String
|
10
|
+
|
11
|
+
@Option(help: "Download screenshots?")
|
12
|
+
var downloadScreenshots = false
|
13
|
+
|
14
|
+
@Option(help: "Figma token")
|
15
|
+
var figmaToken: String
|
16
|
+
|
17
|
+
@Option(help: "Figma screenshots page")
|
18
|
+
var figmaPage: String?
|
19
|
+
|
20
|
+
@Option(help: "Figma project id")
|
21
|
+
var figmaProjectId: String
|
22
|
+
|
23
|
+
@Option(help: "Download preview?")
|
24
|
+
var downloadPreview = false
|
25
|
+
}
|
@@ -0,0 +1,150 @@
|
|
1
|
+
import Common
|
2
|
+
import Foundation
|
3
|
+
|
4
|
+
final class ScreenshotDownloader {
|
5
|
+
|
6
|
+
private let outputURL: URL
|
7
|
+
private let token: String
|
8
|
+
private let projectId: String
|
9
|
+
private let api: Api
|
10
|
+
private let cacheURL: URL
|
11
|
+
|
12
|
+
init(figmaApi: Api, outputURL: URL, token: String, projectId: String) {
|
13
|
+
self.outputURL = outputURL
|
14
|
+
self.token = token
|
15
|
+
self.projectId = projectId
|
16
|
+
self.api = figmaApi
|
17
|
+
|
18
|
+
self.cacheURL = self.outputURL.appendingPathComponent("screenshots_cache")
|
19
|
+
let fm = FileManager.default
|
20
|
+
try? fm.createDirectory(at: self.cacheURL, withIntermediateDirectories: true, attributes: [:])
|
21
|
+
}
|
22
|
+
|
23
|
+
private func downloadIds(_ ids: [String], repeatCount: Int = 5, scale: Int) -> Images? {
|
24
|
+
if repeatCount < 0 {
|
25
|
+
return nil
|
26
|
+
}
|
27
|
+
do {
|
28
|
+
let images = try self.api.images(
|
29
|
+
token: self.token,
|
30
|
+
projectId: self.projectId,
|
31
|
+
ids: ids,
|
32
|
+
scale: scale
|
33
|
+
)
|
34
|
+
if let err = images.err {
|
35
|
+
print("⛔️ Download error \(repeatCount - 1), try one more time: \(err)")
|
36
|
+
return self.downloadIds(ids, repeatCount: repeatCount - 1, scale: scale)
|
37
|
+
} else {
|
38
|
+
return images
|
39
|
+
}
|
40
|
+
} catch {
|
41
|
+
print("⛔️ Download batch error \(repeatCount - 1), try one more time after 15 sec: \(error.locd)")
|
42
|
+
Thread.sleep(forTimeInterval: 15)
|
43
|
+
return self.downloadIds(ids, repeatCount: repeatCount - 1, scale: scale)
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
func download(ids: [String], scale: Int) -> [Images] {
|
48
|
+
let downloadIDs = ids.unique
|
49
|
+
let batch = 10
|
50
|
+
var allImages = [Images]()
|
51
|
+
for idx in stride(from: downloadIDs.indices.lowerBound, to: downloadIDs.indices.upperBound, by: batch) {
|
52
|
+
print("⬇️ Fetching image batch: \(idx)")
|
53
|
+
let subsequence = downloadIDs[idx..<min(idx.advanced(by: batch), downloadIDs.count)]
|
54
|
+
if let images = self.downloadIds(Array(subsequence), repeatCount: 6, scale: scale) {
|
55
|
+
allImages.append(images)
|
56
|
+
self.downloadImages(images)
|
57
|
+
} else {
|
58
|
+
print("💥 Download batch error, maybe we should limit requests other way")
|
59
|
+
exit(1)
|
60
|
+
}
|
61
|
+
}
|
62
|
+
return allImages
|
63
|
+
}
|
64
|
+
|
65
|
+
private func downloadImages(_ images: Images) {
|
66
|
+
DispatchQueue.global().async {
|
67
|
+
if let images = images.images {
|
68
|
+
_ = DownloadBatch(images: images, url: self.cacheURL).download()
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
func download(screens: [Figma.Screen]) throws {
|
74
|
+
var imageIDs2x = [String]()
|
75
|
+
var imageIDs3x = [String]()
|
76
|
+
|
77
|
+
for screen in screens {
|
78
|
+
switch screen.device.scale {
|
79
|
+
case 2:
|
80
|
+
imageIDs2x.append(screen.id)
|
81
|
+
case 3:
|
82
|
+
imageIDs3x.append(screen.id)
|
83
|
+
default:
|
84
|
+
fatalError("🚨Unknown scale \(screen.device.scale)")
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
var allImages = [Images]()
|
89
|
+
allImages += self.download(ids: imageIDs2x, scale: 2)
|
90
|
+
allImages += self.download(ids: imageIDs3x, scale: 3)
|
91
|
+
|
92
|
+
var allImagesKeys = [String: String]()
|
93
|
+
allImages
|
94
|
+
.compactMap { $0.images }
|
95
|
+
.filter { !$0.isEmpty }
|
96
|
+
.forEach { (images) in
|
97
|
+
for image in images {
|
98
|
+
allImagesKeys[image.key] = image.value
|
99
|
+
}
|
100
|
+
}
|
101
|
+
let imageData = DownloadBatch(images: allImagesKeys, url: self.cacheURL).download()
|
102
|
+
|
103
|
+
let screenshotsURL = self.outputURL.appendingPathComponent("screenshots")
|
104
|
+
let fm = FileManager.default
|
105
|
+
do {
|
106
|
+
try fm.removeItem(at: screenshotsURL)
|
107
|
+
} catch {
|
108
|
+
print("Remove screenshots error: \(error)")
|
109
|
+
}
|
110
|
+
try fm.createDirectory(at: screenshotsURL, withIntermediateDirectories: true, attributes: [:])
|
111
|
+
print("ℹ️ Process screenshots at \(screenshotsURL)")
|
112
|
+
for screen in screens {
|
113
|
+
|
114
|
+
let localeURL = screenshotsURL.localeURL(for: screen)
|
115
|
+
do {
|
116
|
+
try fm.createDirectory(at: localeURL, withIntermediateDirectories: true, attributes: [:])
|
117
|
+
|
118
|
+
if let data = imageData[screen.id] {
|
119
|
+
print("ℹ️ Save screenshot \(localeURL.lastPathComponent)/\(screen.fileName)")
|
120
|
+
do {
|
121
|
+
try data.write(to: localeURL.appendingPathComponent(screen.fileName))
|
122
|
+
} catch {
|
123
|
+
print("⛔️ Save screenshot error: \(error.locd)")
|
124
|
+
}
|
125
|
+
}
|
126
|
+
} catch {
|
127
|
+
print("⛔️ Create locale folder error: \(error.locd)")
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
}
|
133
|
+
|
134
|
+
extension URL {
|
135
|
+
func localeURL(for screen: Figma.Screen) -> URL {
|
136
|
+
var url = self
|
137
|
+
if screen.device.isIMessage {
|
138
|
+
// скриншоты для iMessage должны лежать в папке iMessage/Locale/###.jpg
|
139
|
+
url.appendPathComponent("iMessage")
|
140
|
+
}
|
141
|
+
url.appendPathComponent(screen.locale)
|
142
|
+
return url
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
extension String {
|
147
|
+
var cacheName: String {
|
148
|
+
"\(self.MD5String).jpg"
|
149
|
+
}
|
150
|
+
}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import Foundation
|
2
|
+
import Common
|
3
|
+
|
4
|
+
do {
|
5
|
+
let options = ResourcesParser.parseOrExit()
|
6
|
+
let figmaApi = Api(baseURL: "https://api.figma.com/v1")
|
7
|
+
|
8
|
+
NSSetUncaughtExceptionHandler { (exception) in
|
9
|
+
let stack = exception.callStackReturnAddresses
|
10
|
+
print("Stack trace: \(stack)")
|
11
|
+
}
|
12
|
+
|
13
|
+
let deploys = try Deploy.fromTSV(options.tsv)
|
14
|
+
|
15
|
+
let output = (options.output as NSString).expandingTildeInPath
|
16
|
+
let outputURL = URL(fileURLWithPath: output)
|
17
|
+
let metadataURL = outputURL.appendingPathComponent("metadata")
|
18
|
+
let fm = FileManager.default
|
19
|
+
try fm.createDirectory(at: metadataURL, withIntermediateDirectories: true, attributes: [:])
|
20
|
+
|
21
|
+
print("Process metadate at \(metadataURL)")
|
22
|
+
for deploy in deploys {
|
23
|
+
let locale = metadataURL.appendingPathComponent(deploy[.locale])
|
24
|
+
|
25
|
+
do {
|
26
|
+
try fm.createDirectory(at: locale, withIntermediateDirectories: true, attributes: [:])
|
27
|
+
deploy.createFiles(at: locale)
|
28
|
+
} catch {
|
29
|
+
print("Create locale error: \(error)")
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
if options.downloadScreenshots, let pageId = options.figmaPage {
|
34
|
+
print("Load figma screenshots data")
|
35
|
+
|
36
|
+
let pages = try figmaApi.pages(token: options.figmaToken, projectId: options.figmaProjectId, page: pageId)
|
37
|
+
let screens = pages.screens(for: pageId)
|
38
|
+
print("Download figma screenshots data")
|
39
|
+
let downloader = ScreenshotDownloader(
|
40
|
+
figmaApi: figmaApi,
|
41
|
+
outputURL: outputURL,
|
42
|
+
token: options.figmaToken,
|
43
|
+
projectId: options.figmaProjectId
|
44
|
+
)
|
45
|
+
try downloader.download(screens: screens)
|
46
|
+
}
|
47
|
+
|
48
|
+
if options.downloadPreview {
|
49
|
+
let downloader = PreviewDownloader(outputURL: outputURL)
|
50
|
+
try downloader.download(deploys: deploys)
|
51
|
+
}
|
52
|
+
|
53
|
+
} catch {
|
54
|
+
print("\(error.locd)")
|
55
|
+
exit(1)
|
56
|
+
}
|
57
|
+
exit(0)
|
58
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ETLane
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.46
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- teanet
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: 'Xcode helper for upload builds and metadata
|
14
14
|
|
@@ -20,9 +20,32 @@ extra_rdoc_files: []
|
|
20
20
|
files:
|
21
21
|
- Lanes/CommonFastfile
|
22
22
|
- Lanes/ExampleAppfile
|
23
|
+
- Lanes/actions/README.md
|
24
|
+
- Lanes/actions/add_keys_to_lokalise.rb
|
25
|
+
- Lanes/actions/android/README.md
|
26
|
+
- Lanes/actions/android/lokalise_download.rb
|
27
|
+
- Lanes/actions/android/lokalise_upload.rb
|
28
|
+
- Lanes/actions/lokalise.rb
|
29
|
+
- Lanes/actions/lokalise_metadata.rb
|
30
|
+
- Lanes/actions/lokalise_upload.rb
|
31
|
+
- Lanes/actions/previews.rb
|
23
32
|
- Scripts/Package.resolved
|
24
33
|
- Scripts/Package.swift
|
25
34
|
- Scripts/README.md
|
35
|
+
- Scripts/Sources/Common/Api.swift
|
36
|
+
- Scripts/Sources/Common/Array.swift
|
37
|
+
- Scripts/Sources/Common/Error.swift
|
38
|
+
- Scripts/Sources/Common/MD5.swift
|
39
|
+
- Scripts/Sources/Resources/Api+Figma.swift
|
40
|
+
- Scripts/Sources/Resources/Deploy.swift
|
41
|
+
- Scripts/Sources/Resources/Device.swift
|
42
|
+
- Scripts/Sources/Resources/DownloadBatch.swift
|
43
|
+
- Scripts/Sources/Resources/FigmaPages.swift
|
44
|
+
- Scripts/Sources/Resources/Images.swift
|
45
|
+
- Scripts/Sources/Resources/PreviewDownloader.swift
|
46
|
+
- Scripts/Sources/Resources/ResourcesParser.swift
|
47
|
+
- Scripts/Sources/Resources/ScreenshotDownloader.swift
|
48
|
+
- Scripts/Sources/Resources/main.swift
|
26
49
|
homepage: https://github.com/teanet/ETLane
|
27
50
|
licenses:
|
28
51
|
- MIT
|