Skip to content

Commit 947f855

Browse files
committed
Make the L10n CLI tool generate any missing target directories
1 parent 6e75f2d commit 947f855

File tree

2 files changed

+63
-56
lines changed

2 files changed

+63
-56
lines changed

RELEASE_NOTES.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,12 @@ Beta version tags and releases are removed after the next minor or major version
1313

1414
## 2.0.1
1515

16-
This version makes `StringCatalogKeyBuilder` tool independent of `SwiftPackageScripts`.
17-
18-
This solves a bug where the script would crash in other packages, due to a missing path.
16+
This version makes `StringCatalogKeyBuilder` tool independent of `SwiftPackageScripts`. This solves a bug where the script would crash in other packages, due to a missing path.
1917

2018
## 🐛 Bug Fixes
2119

2220
* `tools/StringCatalogKeyBuilder` no longer needs the main package to function.
21+
* `tools/StringCatalogKeyBuilder` no longer fails if the target folder doesn't exist.
2322

2423

2524

scripts/tools/StringCatalogKeyBuilder/Sources/StringCatalogKeyBuilder/StringCatalogParserCommand.swift

Lines changed: 61 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,82 +4,90 @@ import Foundation
44
/// This command can be used to parse a string catalog and generate
55
/// Swift code that allows other targets to access its internal keys.
66
struct StringCatalogParserCommand: ParsableCommand {
7-
static let configuration = CommandConfiguration(
8-
commandName: "l10n-gen",
9-
abstract: "Generate Swift code for a string catalog in any package.",
10-
usage: """
7+
static let configuration = CommandConfiguration(
8+
commandName: "l10n-gen",
9+
abstract: "Generate Swift code for a string catalog in any package.",
10+
usage: """
1111
swift run l10n-gen --from /path/to/catalog.json --to /path/to/output.swift [--root <ROOT_NAMESPACE>]
1212
swift run l10n-gen --package /path/to/package/ --catalog package/relative/catalog/path --target package/relative/file/path [--root <ROOT_NAMESPACE>]
1313
"""
14-
)
14+
)
1515

16-
@OptionGroup var packageOptions: PackageOptions
17-
@OptionGroup var pathOptions: PathOptions
16+
@OptionGroup var packageOptions: PackageOptions
17+
@OptionGroup var pathOptions: PathOptions
1818

19-
@Option var root: String = "l10n"
19+
@Option var root: String = "l10n"
2020

21-
func run() throws {
22-
print("\nGenerating code...\n")
23-
if try packageOptions.tryExecute(withRootNamespace: root) { return }
24-
if try pathOptions.tryExecute(withRootNamespace: root) { return }
25-
fatalError("No matching operation. Aborting.")
26-
}
21+
func run() throws {
22+
print("\nGenerating code...\n")
23+
if try packageOptions.tryExecute(withRootNamespace: root) { return }
24+
if try pathOptions.tryExecute(withRootNamespace: root) { return }
25+
fatalError("No matching operation. Aborting.")
26+
}
2727
}
2828

2929
/// These options are used when using the `--package` argument.
3030
struct PackageOptions: ParsableArguments {
31-
@Option(name: .long, help: "A command-relative path to a Swift Package.")
32-
var package: String?
31+
@Option(name: .long, help: "A command-relative path to a Swift Package.")
32+
var package: String?
3333

34-
@Option(name: .long, help: "A package-relative path to the string catalog.")
35-
var catalog: String?
34+
@Option(name: .long, help: "A package-relative path to the string catalog.")
35+
var catalog: String?
3636

37-
@Option(name: .long, help: "A package-relative path to the target output file.")
38-
var target: String?
37+
@Option(name: .long, help: "A package-relative path to the target output file.")
38+
var target: String?
3939

40-
func tryExecute(
41-
withRootNamespace root: String
42-
) throws -> Bool {
43-
guard let package, let catalog, let target else { return false }
44-
let catalogPath = (package + catalog).cleanPath()
45-
let filePath = (package + target).cleanPath()
46-
try generateCode(from: catalogPath, to: filePath, withRootNamespace: root)
47-
return true
48-
}
40+
func tryExecute(
41+
withRootNamespace root: String
42+
) throws -> Bool {
43+
guard let package, let catalog, let target else { return false }
44+
let catalogPath = (package + catalog).cleanPath()
45+
let filePath = (package + target).cleanPath()
46+
try generateCode(from: catalogPath, to: filePath, withRootNamespace: root)
47+
return true
48+
}
4949
}
5050

5151
/// These options are used when using the `--from` and `--to` arguments.
5252
struct PathOptions: ParsableArguments {
53-
@Option(name: .long, help: "A command-relative path to a source string catalog.")
54-
var from: String?
53+
@Option(name: .long, help: "A command-relative path to a source string catalog.")
54+
var from: String?
5555

56-
@Option(name: .long, help: "A command-relative path to a target output file.")
57-
var to: String?
56+
@Option(name: .long, help: "A command-relative path to a target output file.")
57+
var to: String?
5858

59-
func tryExecute(
60-
withRootNamespace root: String
61-
) throws -> Bool {
62-
guard let from, let to else { return false }
63-
try generateCode(from: from, to: to, withRootNamespace: root)
64-
return true
65-
}
59+
func tryExecute(
60+
withRootNamespace root: String
61+
) throws -> Bool {
62+
guard let from, let to else { return false }
63+
try generateCode(from: from, to: to, withRootNamespace: root)
64+
return true
65+
}
6666
}
6767

6868
extension ParsableArguments {
69-
func generateCode(
70-
from catalogPath: String,
71-
to filePath: String,
72-
withRootNamespace root: String
73-
) throws {
74-
print("Generating code from \"\(catalogPath)\" to \"\(filePath)\"...\n")
75-
let stringCatalog = try StringCatalog(path: catalogPath)
76-
let code = stringCatalog.generatePublicKeyWrappers(withRootNamespace: root)
77-
try code.write(toFile: filePath, atomically: true, encoding: .utf8)
78-
}
69+
func generateCode(
70+
from catalogPath: String,
71+
to filePath: String,
72+
withRootNamespace root: String
73+
) throws {
74+
// Generate wrappers
75+
print("Generating code from \"\(catalogPath)\" to \"\(filePath)\"...\n")
76+
let stringCatalog = try StringCatalog(path: catalogPath)
77+
let code = stringCatalog.generatePublicKeyWrappers(withRootNamespace: root)
78+
79+
// Create parent directory if it doesn't exist
80+
let url = URL(fileURLWithPath: filePath)
81+
let directory = url.deletingLastPathComponent()
82+
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
83+
84+
// Write code to file.
85+
try code.write(toFile: filePath, atomically: true, encoding: .utf8)
86+
}
7987
}
8088

8189
private extension String {
82-
func cleanPath() -> String {
83-
replacingOccurrences(of: "//", with: "/")
84-
}
90+
func cleanPath() -> String {
91+
replacingOccurrences(of: "//", with: "/")
92+
}
8593
}

0 commit comments

Comments
 (0)