com.elestrago.unity.package-tools 2.5.2 → 2.5.3

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.
Files changed (28) hide show
  1. package/CAHNGELOG.md +21 -0
  2. package/Documentation~/api.md +156 -66
  3. package/Documentation~/examples/ciutils-exportlegacypackage.md +32 -0
  4. package/Documentation~/examples/ciutils-exportpackagesource.md +38 -0
  5. package/Documentation~/examples/ciutils-generate.md +13 -8
  6. package/Documentation~/examples/ciutils-listconfigs.md +36 -0
  7. package/Documentation~/examples/packagetoolapi-exportlegacypackage.md +39 -0
  8. package/Documentation~/examples/packagetoolapi-exportpackagesource.md +40 -0
  9. package/Documentation~/examples/packagetoolapi-findconfig.md +46 -0
  10. package/Documentation~/examples/packagetoolapi-generateversionconstants.md +42 -0
  11. package/Documentation~/examples/packagetoolapi-getconfig.md +37 -0
  12. package/Documentation~/examples/packagetoolapi-getconfigs.md +36 -0
  13. package/Documentation~/examples/preparedll.md +1 -1
  14. package/Documentation~/examples.md +12 -1
  15. package/Documentation~/manual.md +39 -23
  16. package/Editor/CIUtils.cs +273 -74
  17. package/Editor/EditorConstants.cs +21 -1
  18. package/Editor/Inspectors/PackageManifestConfigInspector.cs +16 -3
  19. package/Editor/PackageToolApi.cs +141 -0
  20. package/Editor/PackageToolApi.cs.meta +11 -0
  21. package/Editor/Tools/CIResultModel.cs +107 -0
  22. package/Editor/Tools/CIResultModel.cs.meta +11 -0
  23. package/Editor/Tools/CodeGenTools.cs +8 -2
  24. package/Editor/Tools/FileTools.cs +76 -46
  25. package/Editor/Tools/UnityFileTools.cs +16 -2
  26. package/README.md +17 -8
  27. package/Samples~/ClaudeSkills/unity-package-docs/SKILL.md +6 -1
  28. package/package.json +4 -4
@@ -0,0 +1,107 @@
1
+ using System.Collections.Generic;
2
+ using System.IO;
3
+ using Newtonsoft.Json;
4
+ using UnityEngine;
5
+
6
+ namespace PackageTool.Tools
7
+ {
8
+ /// <summary>
9
+ /// The outcome of processing a single <see cref="PackageManifestConfig"/> during a command-line run.
10
+ /// Serialized to the file passed in the 'resultpath' argument so that callers do not have to parse the
11
+ /// Unity log.
12
+ /// </summary>
13
+ internal sealed class CIResultModel
14
+ {
15
+ [JsonProperty("selector")] public string Selector;
16
+ [JsonProperty("configId")] public string ConfigId;
17
+ [JsonProperty("configName")] public string ConfigName;
18
+ [JsonProperty("packageName")] public string PackageName;
19
+ [JsonProperty("packageVersion")] public string PackageVersion;
20
+ [JsonProperty("success")] public bool Success;
21
+ [JsonProperty("packageSourcePath")] public string PackageSourcePath;
22
+ [JsonProperty("legacyPackagePath")] public string LegacyPackagePath;
23
+ [JsonProperty("versionConstantsPath")] public string VersionConstantsPath;
24
+ [JsonProperty("error")] public string Error;
25
+
26
+ public static CIResultModel CreateForConfig(string selector, PackageManifestConfig config)
27
+ {
28
+ return new CIResultModel
29
+ {
30
+ Selector = selector,
31
+ ConfigId = config.Id,
32
+ ConfigName = config.name,
33
+ PackageName = config.packageName,
34
+ PackageVersion = config.packageVersion,
35
+ Success = true
36
+ };
37
+ }
38
+
39
+ public static CIResultModel CreateFailure(string selector, string error)
40
+ {
41
+ return new CIResultModel
42
+ {
43
+ Selector = selector,
44
+ Success = false,
45
+ Error = error
46
+ };
47
+ }
48
+ }
49
+
50
+ /// <summary>
51
+ /// Describes a <see cref="PackageManifestConfig"/> in the project for command-line callers.
52
+ /// </summary>
53
+ internal sealed class CIConfigModel
54
+ {
55
+ [JsonProperty("id")] public string Id;
56
+ [JsonProperty("name")] public string Name;
57
+ [JsonProperty("packageName")] public string PackageName;
58
+ [JsonProperty("displayName")] public string DisplayName;
59
+ [JsonProperty("packageVersion")] public string PackageVersion;
60
+ [JsonProperty("sourcePath")] public string SourcePath;
61
+ [JsonProperty("packageDestinationPath")] public string PackageDestinationPath;
62
+ [JsonProperty("legacyPackageDestinationPath")] public string LegacyPackageDestinationPath;
63
+
64
+ public static CIConfigModel CreateFromConfig(PackageManifestConfig config)
65
+ {
66
+ return new CIConfigModel
67
+ {
68
+ Id = config.Id,
69
+ Name = config.name,
70
+ PackageName = config.packageName,
71
+ DisplayName = config.displayName,
72
+ PackageVersion = config.packageVersion,
73
+ SourcePath = config.sourcePath,
74
+ PackageDestinationPath = config.packageDestinationPath,
75
+ LegacyPackageDestinationPath = config.legacyPackageDestinationPath
76
+ };
77
+ }
78
+ }
79
+
80
+ /// <summary>
81
+ /// Helper methods for writing command-line result files.
82
+ /// </summary>
83
+ internal static class CIResultTools
84
+ {
85
+ private const string WRITE_ERROR_FORMAT = "[Package Tools] Could not write the result file to [{0}]:\n\n{1}";
86
+
87
+ public static void WriteResultFile<T>(string resultPath, IReadOnlyList<T> results)
88
+ {
89
+ if (string.IsNullOrEmpty(resultPath))
90
+ return;
91
+
92
+ try
93
+ {
94
+ var fullPath = Path.GetFullPath(resultPath);
95
+ var directoryPath = Path.GetDirectoryName(fullPath);
96
+ if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
97
+ Directory.CreateDirectory(directoryPath);
98
+
99
+ File.WriteAllText(fullPath, JsonConvert.SerializeObject(results, Formatting.Indented));
100
+ }
101
+ catch (System.Exception e)
102
+ {
103
+ Debug.LogErrorFormat(WRITE_ERROR_FORMAT, resultPath, e);
104
+ }
105
+ }
106
+ }
107
+ }
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: 57ebe53cd55744cd937151bfe4b7ed2b
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -111,12 +111,16 @@ internal static class VersionConstants
111
111
  private const string NO_PATH_SPECIFIED = "A path must be specified for the VersionConstants.cs file to be written " +
112
112
  "to, otherwise this file will not be created.";
113
113
 
114
- public static void GenerateVersionConstants(PackageManifestConfig config)
114
+ /// <summary>
115
+ /// Writes the VersionConstants.cs file for <paramref name="config"/> and returns its path, or null
116
+ /// when the config has no output path set.
117
+ /// </summary>
118
+ public static string GenerateVersionConstants(PackageManifestConfig config)
115
119
  {
116
120
  if(string.IsNullOrEmpty(config.versionConstantsPath))
117
121
  {
118
122
  Debug.LogWarning(NO_PATH_SPECIFIED);
119
- return;
123
+ return null;
120
124
  }
121
125
 
122
126
  // Create folder/file path info
@@ -140,6 +144,8 @@ internal static class VersionConstants
140
144
 
141
145
  var importPath = Path.Combine(config.versionConstantsPath, FILENAME);
142
146
  AssetDatabase.ImportAsset(importPath);
147
+
148
+ return importPath;
143
149
  }
144
150
  }
145
151
  }
@@ -53,11 +53,38 @@ namespace PackageTool.Tools
53
53
 
54
54
  /// <summary>
55
55
  /// Creates or updates the existing package contents of <see cref="PackageManifestConfig"/>
56
- /// <paramref name="packageManifest"/>.
56
+ /// <paramref name="packageManifest"/>. Failures are logged rather than thrown; callers that need to
57
+ /// know the outcome should use <see cref="CreateOrUpdatePackageSourceOrThrow"/> instead.
57
58
  /// </summary>
58
59
  /// <param name="packageManifest"></param>
59
60
  public static void CreateOrUpdatePackageSource(PackageManifestConfig packageManifest)
60
61
  {
62
+ try
63
+ {
64
+ CreateOrUpdatePackageSourceOrThrow(packageManifest);
65
+ }
66
+ catch (Exception ex)
67
+ {
68
+ Debug.LogErrorFormat(EditorConstants.PACKAGE_UPDATE_ERROR_FORMAT, packageManifest.packageName);
69
+ Debug.LogErrorFormat(packageManifest, ex.ToString());
70
+ }
71
+ }
72
+
73
+ /// <summary>
74
+ /// Creates or updates the existing package contents of <see cref="PackageManifestConfig"/>
75
+ /// <paramref name="packageManifest"/> and returns the path of the written package.json in the
76
+ /// destination folder. Any failure is thrown to the caller.
77
+ /// </summary>
78
+ /// <param name="packageManifest"></param>
79
+ public static string CreateOrUpdatePackageSourceOrThrow(PackageManifestConfig packageManifest)
80
+ {
81
+ if (packageManifest == null)
82
+ throw new ArgumentNullException(nameof(packageManifest));
83
+
84
+ if (string.IsNullOrEmpty(packageManifest.packageDestinationPath))
85
+ throw new InvalidOperationException(
86
+ string.Format(EditorConstants.NO_PACKAGE_DESTINATION_PATH_ERROR_FORMAT, packageManifest.name));
87
+
61
88
  if (!Application.isBatchMode)
62
89
  {
63
90
  EditorUtility.DisplayProgressBar(EditorConstants.PROGRESS_BAR_TITLE, string.Empty, 0f);
@@ -65,35 +92,11 @@ namespace PackageTool.Tools
65
92
 
66
93
  try
67
94
  {
68
- // Created the folders up to the package json path and then create/import the package.json file.
69
- // Its important to have the package.json in the Unity project so that it will have a meta file
70
- // Packages without meta files cause warnings/errors when imported.
71
- var packageManifestAssetPath = AssetDatabase.GetAssetPath(packageManifest);
72
- var parentManifestParentFolderAssetPath = packageManifestAssetPath
73
- .Replace(packageManifest.name, string.Empty)
74
- .Replace(EditorConstants.ASSET_EXTENSION, string.Empty);
75
- var generatedFolderAssetPath = Path.Combine(parentManifestParentFolderAssetPath,
76
- EditorConstants.GENERATED_FOLDER_NAME);
77
- var fullGeneratedFolderAssetPath = Path.GetFullPath(generatedFolderAssetPath);
78
-
79
- if (!Directory.Exists(fullGeneratedFolderAssetPath))
80
- {
81
- Directory.CreateDirectory(fullGeneratedFolderAssetPath);
82
- }
83
-
84
- var packageJsonFolderAssetPath = Path.Combine(generatedFolderAssetPath, packageManifest.Id);
85
- var fullPackageJsonFolderAssetPath = Path.GetFullPath(packageJsonFolderAssetPath);
86
- if (!Directory.Exists(fullPackageJsonFolderAssetPath))
87
- {
88
- Directory.CreateDirectory(fullPackageJsonFolderAssetPath);
89
- }
90
-
91
- var packageJsonAssetPath =
92
- Path.Combine(packageJsonFolderAssetPath, EditorConstants.PACKAGE_JSON_FILENAME);
93
- var fullPackageJsonAssetPath = Path.GetFullPath(packageJsonAssetPath);
94
-
95
- File.WriteAllText(fullPackageJsonAssetPath, packageManifest.GenerateJson());
96
- AssetDatabase.ImportAsset(packageJsonAssetPath, ImportAssetOptions.ForceUpdate);
95
+ // The package.json is written into the package source folder so that it lives in the Unity
96
+ // project and gets a meta file. Packages without meta files cause warnings/errors when
97
+ // imported, and keeping it in the source folder means both the package source export and the
98
+ // legacy package export pick it up along with the rest of the source content.
99
+ WritePackageJsonToSource(packageManifest);
97
100
 
98
101
  // If the directory exists, delete its contents or make the directory.
99
102
  if (Directory.Exists(packageManifest.packageDestinationPath))
@@ -105,17 +108,6 @@ namespace PackageTool.Tools
105
108
  Directory.CreateDirectory(packageManifest.packageDestinationPath);
106
109
  }
107
110
 
108
- // Copy over the package json and meta file
109
- var destinationPackageJsonPath =
110
- Path.Combine(packageManifest.packageDestinationPath, EditorConstants.PACKAGE_JSON_FILENAME);
111
- File.Copy(fullPackageJsonAssetPath, destinationPackageJsonPath);
112
-
113
- var packageJsonMetaPath = string.Format(EditorConstants.META_FORMAT, fullPackageJsonAssetPath);
114
-
115
- File.Copy(packageJsonMetaPath,
116
- Path.Combine(packageManifest.packageDestinationPath,
117
- string.Format(EditorConstants.META_FORMAT, EditorConstants.PACKAGE_JSON_FILENAME)));
118
-
119
111
  // Copy over all directory and file content from source to destination.
120
112
  var normalizedDestinationPath = Path.GetFullPath(packageManifest.packageDestinationPath);
121
113
 
@@ -128,17 +120,17 @@ namespace PackageTool.Tools
128
120
  CopySamplesToDirectory(packageManifest);
129
121
  StampLocalDocCopiesForAgents(packageManifest);
130
122
 
123
+ var destinationPackageJsonPath =
124
+ Path.Combine(packageManifest.packageDestinationPath, EditorConstants.PACKAGE_JSON_FILENAME);
125
+
131
126
  Debug.LogFormat(EditorConstants.PACKAGE_UPDATE_SUCCESS_FORMAT, packageManifest.packageName);
132
127
 
133
128
  if (!Application.isBatchMode)
134
129
  {
135
130
  EditorUtility.RevealInFinder(destinationPackageJsonPath);
136
131
  }
137
- }
138
- catch (Exception ex)
139
- {
140
- Debug.LogErrorFormat(EditorConstants.PACKAGE_UPDATE_ERROR_FORMAT, packageManifest.packageName);
141
- Debug.LogErrorFormat(packageManifest, ex.ToString());
132
+
133
+ return destinationPackageJsonPath;
142
134
  }
143
135
  finally
144
136
  {
@@ -150,6 +142,44 @@ namespace PackageTool.Tools
150
142
  }
151
143
  }
152
144
 
145
+ /// <summary>
146
+ /// Writes the generated package.json of <paramref name="packageManifest"/> into its
147
+ /// <see cref="PackageManifestConfig.sourcePath"/> and imports it so a meta file is created for it.
148
+ /// Returns the project-relative asset path of the written file.
149
+ /// </summary>
150
+ /// <param name="packageManifest"></param>
151
+ public static string WritePackageJsonToSource(PackageManifestConfig packageManifest)
152
+ {
153
+ if (packageManifest == null)
154
+ throw new ArgumentNullException(nameof(packageManifest));
155
+
156
+ if (string.IsNullOrEmpty(packageManifest.sourcePath))
157
+ throw new InvalidOperationException(
158
+ string.Format(EditorConstants.NO_SOURCE_PATH_ERROR_FORMAT, packageManifest.name));
159
+
160
+ var packageJsonAssetPath = Path.Combine(packageManifest.sourcePath, EditorConstants.PACKAGE_JSON_FILENAME);
161
+ var fullPackageJsonPath = Path.GetFullPath(packageJsonAssetPath);
162
+ var fullSourcePath = Path.GetFullPath(packageManifest.sourcePath);
163
+
164
+ if (!Directory.Exists(fullSourcePath))
165
+ Directory.CreateDirectory(fullSourcePath);
166
+
167
+ File.WriteAllText(fullPackageJsonPath, packageManifest.GenerateJson());
168
+ AssetDatabase.ImportAsset(packageJsonAssetPath, ImportAssetOptions.ForceUpdate);
169
+
170
+ // Imports are deferred while an AssetDatabase.StartAssetEditing scope is open, which can leave the
171
+ // meta file missing when the export copies the source folder over to the destination.
172
+ if (!File.Exists(string.Format(EditorConstants.META_FORMAT, fullPackageJsonPath)))
173
+ {
174
+ AssetDatabase.Refresh();
175
+
176
+ if (!File.Exists(string.Format(EditorConstants.META_FORMAT, fullPackageJsonPath)))
177
+ Debug.LogWarningFormat(EditorConstants.PACKAGE_JSON_META_MISSING_FORMAT, packageJsonAssetPath);
178
+ }
179
+
180
+ return packageJsonAssetPath;
181
+ }
182
+
153
183
  public static void CopyDocumentationToDirectory(PackageManifestConfig packageManifest)
154
184
  {
155
185
  var normalizedSourcePath = Path.GetFullPath(packageManifest.sourcePath);
@@ -22,6 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  SOFTWARE.
23
23
  */
24
24
 
25
+ using System;
25
26
  using System.Collections.Generic;
26
27
  using System.IO;
27
28
  using System.Linq;
@@ -37,11 +38,22 @@ namespace PackageTool.Tools
37
38
  {
38
39
  /// <summary>
39
40
  /// Gather all of the files/folders for the package and export them to the pre-defined location
40
- /// at <see cref="PackageManifestConfig.legacyPackageDestinationPath"/>.
41
+ /// at <see cref="PackageManifestConfig.legacyPackageDestinationPath"/>. Returns the path of the
42
+ /// exported unity package.
41
43
  /// </summary>
42
44
  /// <param name="config"></param>
43
- public static void CompileLegacyPackage(PackageManifestConfig config)
45
+ public static string CompileLegacyPackage(PackageManifestConfig config)
44
46
  {
47
+ if (config == null)
48
+ throw new ArgumentNullException(nameof(config));
49
+
50
+ if (string.IsNullOrEmpty(config.legacyPackageDestinationPath))
51
+ throw new InvalidOperationException(
52
+ string.Format(EditorConstants.NO_LEGACY_DESTINATION_PATH_ERROR_FORMAT, config.name));
53
+
54
+ // Written before the documentation copy so its trailing AssetDatabase.Refresh imports the
55
+ // package.json, which otherwise would not be part of the exported asset paths.
56
+ FileTools.WritePackageJsonToSource(config);
45
57
  FileTools.CopyDocumentationToDirectory(config);
46
58
 
47
59
  // Gathers all of the files/folders for export as a legacy package.
@@ -72,6 +84,8 @@ namespace PackageTool.Tools
72
84
  EditorUtility.RevealInFinder(finalFilePath);
73
85
  EditorUtility.ClearProgressBar();
74
86
  }
87
+
88
+ return finalFilePath;
75
89
  }
76
90
 
77
91
  /// <summary>
package/README.md CHANGED
@@ -29,7 +29,7 @@ Add the package to `Packages/manifest.json`:
29
29
  }
30
30
  ],
31
31
  "dependencies": {
32
- "com.elestrago.unity.package-tools": "2.5.2"
32
+ "com.elestrago.unity.package-tools": "2.5.3"
33
33
  }
34
34
  }
35
35
  ```
@@ -43,17 +43,26 @@ Replace the registry URL above with your scoped registry, or remove the `scopedR
43
43
  3. Optionally add `dependencies`, `samples`, and `copyEntries` rows in the inspector.
44
44
  4. Click **Export Package Source** to assemble the package; **Export as Legacy Package** to emit a `.unitypackage`; or **Generate VersionConstants.cs** to write a versions file at `versionConstantsPath`.
45
45
 
46
- For CI, invoke `PackageTool.CIUtils.Generate` in batch mode and pass `version=<semver>` to override the asset's version on a per-run basis:
46
+ To export from your own editor code, call `PackageTool.PackageToolApi` the same methods the inspector buttons use:
47
47
 
48
48
  ```csharp
49
- // Unity batch-mode CLI:
50
- // unity -batchmode -quit -projectPath . \
51
- // -executeMethod PackageTool.CIUtils.Generate \
52
- // version=1.2.3 generateversionconstants=true
53
-
54
49
  using PackageTool;
55
50
 
56
- CIUtils.Generate();
51
+ // Selectors match the config id, the package name, or the config asset name.
52
+ var config = PackageToolApi.GetConfig("com.elestrago.unity.package-tools");
53
+
54
+ PackageToolApi.ExportPackageSource(config, version: "1.2.3");
55
+ PackageToolApi.ExportLegacyPackage(config);
56
+ ```
57
+
58
+ For CI, invoke the `PackageTool.CIUtils` entry points in batch mode. `Generate` exports both outputs for every config; `ExportPackageSource`, `ExportLegacyPackage` and `ListConfigs` are the narrower entry points. Pass `resultpath=<file>` to get a JSON report instead of scraping the log:
59
+
60
+ ```bash
61
+ unity -batchmode -quit -projectPath . \
62
+ -executeMethod PackageTool.CIUtils.ExportPackageSource \
63
+ id=com.elestrago.unity.package-tools \
64
+ version=1.2.3 \
65
+ resultpath=/tmp/package-tool-result.json
57
66
  ```
58
67
 
59
68
  ## Documentation
@@ -71,7 +71,12 @@ find . -type f -name package.json \
71
71
 
72
72
  - **Exactly one match** → that file is the package manifest. Its containing directory is the **package root**. Read it.
73
73
  - **Zero matches but `Assets/**/PackageManifestConfig.asset` exists** (package-tool projects pre-first-export) → use the config asset as the metadata source. The `sourcePath` field is the package root. Note in `manual.md` that the `package.json` is generated to `<packageDestinationPath>/` on export.
74
- - **More than one match, or zero matches with no config** → abort. Print the matches found and ask the user to disambiguate via `package=<path>`.
74
+ - **More than one match** → a package-tool project exports a copy of `package.json` into its
75
+ `packageDestinationPath` (e.g. `Release/`), so the same package is legitimately found twice. If exactly one
76
+ match lies under `Assets/`, that one is the package root and the others are export artifacts — use it and
77
+ print `package-root: <path> (ignored N exported copy/copies)`. Otherwise abort: print the matches found and
78
+ ask the user to disambiguate via `package=<path>`.
79
+ - **Zero matches with no config** → abort. Print what was searched and ask the user for `package=<path>`.
75
80
 
76
81
  ### Step 2 — Read metadata
77
82
 
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "com.elestrago.unity.package-tools",
3
- "version": "2.5.2",
3
+ "version": "2.5.3",
4
4
  "displayName": "Package Tool",
5
5
  "description": "Tool for create unity packages",
6
6
  "category": "unity",
7
7
  "unity": "2021.3",
8
8
  "homepage": "https://gitlab.com/elestrago-pkg/package-tool",
9
- "documentationUrl": "https://gitlab.com/elestrago-pkg/package-tool/-/blob/2.5.2/README.md",
10
- "changelogUrl": "https://gitlab.com/elestrago-pkg/package-tool/-/blob/2.5.2/CHANGELOG.md",
11
- "licensesUrl": "https://gitlab.com/elestrago-pkg/package-tool/-/blob/2.5.2/LICENSE",
9
+ "documentationUrl": "https://gitlab.com/elestrago-pkg/package-tool/-/blob/2.5.3/README.md",
10
+ "changelogUrl": "https://gitlab.com/elestrago-pkg/package-tool/-/blob/2.5.3/CHANGELOG.md",
11
+ "licensesUrl": "https://gitlab.com/elestrago-pkg/package-tool/-/blob/2.5.3/LICENSE",
12
12
  "license": "MIT",
13
13
  "keywords": [
14
14
  "unity",