diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..962aa38 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +* -text + +*.cs text eol=lf diff=csharp +*.shader text eol=lf +*.cginc text eol=lf +*.hlsl text eol=lf +*.compute text eol=lf + +*.meta text eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba7da1a --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Windows +Thumbs.db +Desktop.ini +/*.csproj +/*.sln + +# macOS +.DS_Store + +# Vim +*.swp + +# Unity +/Logs +/Library +/Temp +.vs +obj diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100755 index 0000000..08c7c8d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/CHANGELOG.md.meta b/CHANGELOG.md.meta new file mode 100755 index 0000000..c70ee3c --- /dev/null +++ b/CHANGELOG.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 06608ad179f2043e5a26ec668de262d6 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..b4304d3 --- /dev/null +++ b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5a27e70b9c8a14cd2a39fd440ae97c3c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Coffee.GitDependencyResolver.asmdef b/Editor/Coffee.GitDependencyResolver.asmdef new file mode 100755 index 0000000..0e18494 --- /dev/null +++ b/Editor/Coffee.GitDependencyResolver.asmdef @@ -0,0 +1,14 @@ +{ + "name": "Coffee.GitDependencyResolver", + "references": [], + "optionalUnityReferences": [], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [] +} \ No newline at end of file diff --git a/Editor/Coffee.GitDependencyResolver.asmdef.meta b/Editor/Coffee.GitDependencyResolver.asmdef.meta new file mode 100644 index 0000000..5a91ea8 --- /dev/null +++ b/Editor/Coffee.GitDependencyResolver.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b146f8c053ccc45258f4d4be02ef68a8 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/GitDependencyResolver.cs b/Editor/GitDependencyResolver.cs new file mode 100644 index 0000000..16b87ff --- /dev/null +++ b/Editor/GitDependencyResolver.cs @@ -0,0 +1,114 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace Coffee.PackageManager +{ + [InitializeOnLoad] + public static class GitDependencyResolver + { + static GitDependencyResolver () + { + EditorApplication.projectChanged += StartResolve; + StartResolve (); + } + + /// + /// Uninstall unused packages (for auto-installed packages) + /// + static void UninstallUnusedPackages () + { + bool check = true; + while (check) + { + check = false; + + // Collect all dependencies. + var allDependencies = Directory.GetDirectories ("./Library/PackageCache") + .Concat (Directory.GetDirectories ("./Packages")) + .Select (PackageMeta.FromPackageDir) // Convert to PackageMeta + .Where (x => x != null) // Skip null + .SelectMany (x => x.dependencies) // Get all dependencies + .ToArray (); + + // Collect unused pakages. + var unusedPackages = Directory.GetDirectories ("./Packages") + .Where (x => Path.GetFileName (x).StartsWith (".")) // Directory name starts with '.'. This is 'auto-installed package' + .Select (PackageMeta.FromPackageDir) // Convert to PackageMeta + .Where (x => x != null) // Skip null + .Where (x => allDependencies.All (y => y.name != x.name)) // No depended from other packages + .ToArray (); + + // Uninstall unused packages and re-check. + foreach (var p in unusedPackages) + { + check = true; + Debug.LogFormat ("[Resolver] Uninstall unused package: {0} from {1}", p.name, p.path); + FileUtil.DeleteFileOrDirectory (p.path); + } + } + } + + + static void StartResolve () + { + // Uninstall unused packages (for auto-installed packages) + UninstallUnusedPackages (); + + // Collect all installed pakages. + var installedPackages = Directory.GetDirectories ("./Library/PackageCache") + .Concat (Directory.GetDirectories ("./Packages")) + .Select (PackageMeta.FromPackageDir) // Convert to PackageMeta + .Where (x => x != null) // Skip null + .ToArray (); + + // Collect all dependencies. + var dependencies = installedPackages + .SelectMany (x => x.dependencies) // Get all dependencies + .Where (x => !string.IsNullOrEmpty (x.path)); // path (url) is available + + List requestedPackages = new List (); + + // Check all dependencies. + foreach (var dependency in dependencies) + { + // Is the depended package installed already? + bool isInstalled = installedPackages + .Concat (requestedPackages) + .Any (x => dependency.name == x.name && dependency.version <= x.version); + + // Install the depended package later. + if (!isInstalled) + { + Debug.LogFormat ("[Resolver] A dependency package is requested: {0}", dependency.name); + requestedPackages.RemoveAll (x => dependency.name == x.name); + requestedPackages.Add (dependency); + } + } + + // No packages is requested to install. + if (requestedPackages.Count == 0) + return; + + // Install all requested packages. + for (int i = 0; i < requestedPackages.Count; i++) + { + PackageMeta meta = requestedPackages [i]; + EditorUtility.DisplayProgressBar ("Add Package", "Cloning: " + meta.name, i / (float)requestedPackages.Count); + Debug.LogFormat ("[Resolver] A package is cloning: {0}", meta.name); + bool success = GitUtils.ClonePackage (meta); + if (!success) + { + Debug.LogFormat ("[Resolver] Failed to clone: {0}", meta.name); + break; + } + } + + // Recompile the packages + EditorUtility.ClearProgressBar (); + EditorApplication.delayCall += AssetDatabase.Refresh; + } + } +} diff --git a/Editor/GitDependencyResolver.cs.meta b/Editor/GitDependencyResolver.cs.meta new file mode 100644 index 0000000..68b24fd --- /dev/null +++ b/Editor/GitDependencyResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bad84303b06d74f06b7d6ff666e13f91 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/MiniJSON.cs b/Editor/MiniJSON.cs new file mode 100644 index 0000000..1751486 --- /dev/null +++ b/Editor/MiniJSON.cs @@ -0,0 +1,632 @@ +/* + * Copyright (c) 2013 Calvin Rien + * + * Based on the JSON parser by Patrick van Bergen + * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html + * + * Simplified it so that it doesn't throw exceptions + * and can be used in Unity iPhone with maximum code stripping. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace MiniJSON +{ + // Example usage: + // + // using UnityEngine; + // using System.Collections; + // using System.Collections.Generic; + // using MiniJSON; + // + // public class MiniJSONTest : MonoBehaviour { + // void Start () { + // var jsonString = "{ \"array\": [1.44,2,3], " + + // "\"object\": {\"key1\":\"value1\", \"key2\":256}, " + + // "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " + + // "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " + + // "\"int\": 65536, " + + // "\"float\": 3.1415926, " + + // "\"bool\": true, " + + // "\"null\": null }"; + // + // var dict = Json.Deserialize(jsonString) as Dictionary; + // + // Debug.Log("deserialized: " + dict.GetType()); + // Debug.Log("dict['array'][0]: " + ((List) dict["array"])[0]); + // Debug.Log("dict['string']: " + (string) dict["string"]); + // Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles + // Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs + // Debug.Log("dict['unicode']: " + (string) dict["unicode"]); + // + // var str = Json.Serialize(dict); + // + // Debug.Log("serialized: " + str); + // } + // } + + /// + /// This class encodes and decodes JSON strings. + /// Spec. details, see http://www.json.org/ + /// + /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary. + /// All numbers are parsed to doubles. + /// + public static class Json + { + /// + /// Parses the string json into a value + /// + /// A JSON string. + /// An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false + public static object Deserialize (string json) + { + // save the string for debug information + if (json == null) + { + return null; + } + + return Parser.Parse (json); + } + + sealed class Parser : IDisposable + { + const string WORD_BREAK = "{}[],:\""; + + public static bool IsWordBreak (char c) + { + return Char.IsWhiteSpace (c) || WORD_BREAK.IndexOf (c) != -1; + } + + enum TOKEN + { + NONE, + CURLY_OPEN, + CURLY_CLOSE, + SQUARED_OPEN, + SQUARED_CLOSE, + COLON, + COMMA, + STRING, + NUMBER, + TRUE, + FALSE, + NULL + }; + + StringReader json; + + Parser (string jsonString) + { + json = new StringReader (jsonString); + } + + public static object Parse (string jsonString) + { + using (var instance = new Parser (jsonString)) + { + return instance.ParseValue (); + } + } + + public void Dispose () + { + json.Dispose (); + json = null; + } + + Dictionary ParseObject () + { + Dictionary table = new Dictionary (); + + // ditch opening brace + json.Read (); + + // { + while (true) + { + switch (NextToken) + { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.CURLY_CLOSE: + return table; + default: + // name + string name = ParseString (); + if (name == null) + { + return null; + } + + // : + if (NextToken != TOKEN.COLON) + { + return null; + } + // ditch the colon + json.Read (); + + // value + table [name] = ParseValue (); + break; + } + } + } + + List ParseArray () + { + List array = new List (); + + // ditch opening bracket + json.Read (); + + // [ + var parsing = true; + while (parsing) + { + TOKEN nextToken = NextToken; + + switch (nextToken) + { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.SQUARED_CLOSE: + parsing = false; + break; + default: + object value = ParseByToken (nextToken); + + array.Add (value); + break; + } + } + + return array; + } + + object ParseValue () + { + TOKEN nextToken = NextToken; + return ParseByToken (nextToken); + } + + object ParseByToken (TOKEN token) + { + switch (token) + { + case TOKEN.STRING: + return ParseString (); + case TOKEN.NUMBER: + return ParseNumber (); + case TOKEN.CURLY_OPEN: + return ParseObject (); + case TOKEN.SQUARED_OPEN: + return ParseArray (); + case TOKEN.TRUE: + return true; + case TOKEN.FALSE: + return false; + case TOKEN.NULL: + return null; + default: + return null; + } + } + + string ParseString () + { + StringBuilder s = new StringBuilder (); + char c; + + // ditch opening quote + json.Read (); + + bool parsing = true; + while (parsing) + { + + if (json.Peek () == -1) + { + parsing = false; + break; + } + + c = NextChar; + switch (c) + { + case '"': + parsing = false; + break; + case '\\': + if (json.Peek () == -1) + { + parsing = false; + break; + } + + c = NextChar; + switch (c) + { + case '"': + case '\\': + case '/': + s.Append (c); + break; + case 'b': + s.Append ('\b'); + break; + case 'f': + s.Append ('\f'); + break; + case 'n': + s.Append ('\n'); + break; + case 'r': + s.Append ('\r'); + break; + case 't': + s.Append ('\t'); + break; + case 'u': + var hex = new char [4]; + + for (int i = 0; i < 4; i++) + { + hex [i] = NextChar; + } + + s.Append ((char)Convert.ToInt32 (new string (hex), 16)); + break; + } + break; + default: + s.Append (c); + break; + } + } + + return s.ToString (); + } + + object ParseNumber () + { + string number = NextWord; + + if (number.IndexOf ('.') == -1) + { + long parsedInt; + Int64.TryParse (number, out parsedInt); + return parsedInt; + } + + double parsedDouble; + Double.TryParse (number, out parsedDouble); + return parsedDouble; + } + + void EatWhitespace () + { + while (Char.IsWhiteSpace (PeekChar)) + { + json.Read (); + + if (json.Peek () == -1) + { + break; + } + } + } + + char PeekChar + { + get + { + return Convert.ToChar (json.Peek ()); + } + } + + char NextChar + { + get + { + return Convert.ToChar (json.Read ()); + } + } + + string NextWord + { + get + { + StringBuilder word = new StringBuilder (); + + while (!IsWordBreak (PeekChar)) + { + word.Append (NextChar); + + if (json.Peek () == -1) + { + break; + } + } + + return word.ToString (); + } + } + + TOKEN NextToken + { + get + { + EatWhitespace (); + + if (json.Peek () == -1) + { + return TOKEN.NONE; + } + + switch (PeekChar) + { + case '{': + return TOKEN.CURLY_OPEN; + case '}': + json.Read (); + return TOKEN.CURLY_CLOSE; + case '[': + return TOKEN.SQUARED_OPEN; + case ']': + json.Read (); + return TOKEN.SQUARED_CLOSE; + case ',': + json.Read (); + return TOKEN.COMMA; + case '"': + return TOKEN.STRING; + case ':': + return TOKEN.COLON; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return TOKEN.NUMBER; + } + + switch (NextWord) + { + case "false": + return TOKEN.FALSE; + case "true": + return TOKEN.TRUE; + case "null": + return TOKEN.NULL; + } + + return TOKEN.NONE; + } + } + } + + /// + /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string + /// + /// A Dictionary<string, object> / List<object> + /// A JSON encoded string, or null if object 'json' is not serializable + public static string Serialize (object obj) + { + return Serializer.Serialize (obj); + } + + sealed class Serializer + { + StringBuilder builder; + + Serializer () + { + builder = new StringBuilder (); + } + + public static string Serialize (object obj) + { + var instance = new Serializer (); + + instance.SerializeValue (obj); + + return instance.builder.ToString (); + } + + void SerializeValue (object value) + { + IList asList; + IDictionary asDict; + string asStr; + + if (value == null) + { + builder.Append ("null"); + } + else if ((asStr = value as string) != null) + { + SerializeString (asStr); + } + else if (value is bool) + { + builder.Append ((bool)value ? "true" : "false"); + } + else if ((asList = value as IList) != null) + { + SerializeArray (asList); + } + else if ((asDict = value as IDictionary) != null) + { + SerializeObject (asDict); + } + else if (value is char) + { + SerializeString (new string ((char)value, 1)); + } + else + { + SerializeOther (value); + } + } + + void SerializeObject (IDictionary obj) + { + bool first = true; + + builder.Append ('{'); + + foreach (object e in obj.Keys) + { + if (!first) + { + builder.Append (','); + } + + SerializeString (e.ToString ()); + builder.Append (':'); + + SerializeValue (obj [e]); + + first = false; + } + + builder.Append ('}'); + } + + void SerializeArray (IList anArray) + { + builder.Append ('['); + + bool first = true; + + foreach (object obj in anArray) + { + if (!first) + { + builder.Append (','); + } + + SerializeValue (obj); + + first = false; + } + + builder.Append (']'); + } + + void SerializeString (string str) + { + builder.Append ('\"'); + + char [] charArray = str.ToCharArray (); + foreach (var c in charArray) + { + switch (c) + { + case '"': + builder.Append ("\\\""); + break; + case '\\': + builder.Append ("\\\\"); + break; + case '\b': + builder.Append ("\\b"); + break; + case '\f': + builder.Append ("\\f"); + break; + case '\n': + builder.Append ("\\n"); + break; + case '\r': + builder.Append ("\\r"); + break; + case '\t': + builder.Append ("\\t"); + break; + default: + int codepoint = Convert.ToInt32 (c); + if ((codepoint >= 32) && (codepoint <= 126)) + { + builder.Append (c); + } + else + { + builder.Append ("\\u"); + builder.Append (codepoint.ToString ("x4")); + } + break; + } + } + + builder.Append ('\"'); + } + + void SerializeOther (object value) + { + // NOTE: decimals lose precision during serialization. + // They always have, I'm just letting you know. + // Previously floats and doubles lost precision too. + if (value is float) + { + builder.Append (((float)value).ToString ("R")); + } + else if (value is int + || value is uint + || value is long + || value is sbyte + || value is byte + || value is short + || value is ushort + || value is ulong) + { + builder.Append (value); + } + else if (value is double + || value is decimal) + { + builder.Append (Convert.ToDouble (value).ToString ("R")); + } + else + { + SerializeString (value.ToString ()); + } + } + } + } +} \ No newline at end of file diff --git a/Editor/MiniJSON.cs.meta b/Editor/MiniJSON.cs.meta new file mode 100644 index 0000000..bb288e9 --- /dev/null +++ b/Editor/MiniJSON.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08cffd700e9e240d6ac689d9c47498f2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PackageMeta.cs b/Editor/PackageMeta.cs new file mode 100644 index 0000000..d9fd7bf --- /dev/null +++ b/Editor/PackageMeta.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using MiniJSON; +using Semver; + +namespace Coffee.PackageManager +{ + public class PackageMeta + { + public string name { get; private set; } + internal SemVersion version { get; private set; } + public string branch { get; private set; } + public string path { get; private set; } + public PackageMeta [] dependencies { get; private set; } + + public static PackageMeta FromPackageDir (string dir) + { + try + { + Dictionary dict = Json.Deserialize (File.ReadAllText (dir + "/package.json")) as Dictionary; + PackageMeta meta = new PackageMeta () { path = dir, }; + object obj; + + if (dict.TryGetValue ("name", out obj)) + { + meta.name = obj as string; + } + + if (dict.TryGetValue ("version", out obj)) + { + meta.version = obj as string; + } + + if (dict.TryGetValue ("dependencies", out obj)) + { + meta.dependencies = (dict ["dependencies"] as Dictionary) + .Select (x => PackageMeta.FromNameAndUrl (x.Key, (string)x.Value)) + .ToArray (); + } + else + { + meta.dependencies = new PackageMeta [0]; + } + return meta; + } + catch + { + return null; + } + } + + public static PackageMeta FromNameAndUrl (string name, string url) + { + PackageMeta meta = new PackageMeta () { name = name, dependencies = new PackageMeta [0] }; + Match m = Regex.Match (url, "([^#]*)#?(.*)"); + if (m.Success) + { + string first = m.Groups [1].Value; + string second = m.Groups [2].Value; + + if (first.Contains ("://")) + { + meta.path = first; + meta.branch = 0 < second.Length ? second : "HEAD"; + meta.version = meta.branch; + } + else + { + meta.version = first; + } + } + return meta; + } + } +} \ No newline at end of file diff --git a/Editor/PackageMeta.cs.meta b/Editor/PackageMeta.cs.meta new file mode 100644 index 0000000..a4e53a6 --- /dev/null +++ b/Editor/PackageMeta.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c92b3aa6dc55541788f00a9e7ec299df +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/SemVersion.cs b/Editor/SemVersion.cs new file mode 100644 index 0000000..e20862c --- /dev/null +++ b/Editor/SemVersion.cs @@ -0,0 +1,558 @@ +/* +Copyright (c) 2013 Max Hauser + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +using System; +#if !NETSTANDARD +using System.Globalization; +using System.Runtime.Serialization; +using System.Security.Permissions; +#endif +using System.Text.RegularExpressions; + +namespace Semver +{ + /// + /// A semantic version implementation. + /// Conforms to v2.0.0 of http://semver.org/ + /// +#if NETSTANDARD + public sealed class SemVersion : IComparable, IComparable +#else + [Serializable] + public sealed class SemVersion : IComparable, IComparable, ISerializable +#endif + { + static Regex parseEx = + new Regex(@"(?\d+)" + + @"(\.(?\d+))?" + + @"(\.(?\d+))?" + + @"(\-(?
[0-9A-Za-z\-\.]+))?" +
+                @"(\+(?[0-9A-Za-z\-\.]+))?$",
+#if NETSTANDARD
+                RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture);
+#else
+                RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
+#endif
+
+#if !NETSTANDARD
+        /// 
+        /// Initializes a new instance of the  class.
+        /// 
+        /// 
+        /// 
+        /// 
+        private SemVersion(SerializationInfo info, StreamingContext context)
+        {
+            if (info == null) throw new ArgumentNullException("info");
+            var semVersion = Parse(info.GetString("SemVersion"));
+            Major = semVersion.Major;
+            Minor = semVersion.Minor;
+            Patch = semVersion.Patch;
+            Prerelease = semVersion.Prerelease;
+            Build = semVersion.Build;
+        }
+#endif
+
+        /// 
+        /// Initializes a new instance of the  class.
+        /// 
+        /// The major version.
+        /// The minor version.
+        /// The patch version.
+        /// The prerelease version (eg. "alpha").
+        /// The build eg ("nightly.232").
+        public SemVersion(int major, int minor = 0, int patch = 0, string prerelease = "", string build = "")
+        {
+            this.Major = major;
+            this.Minor = minor;
+            this.Patch = patch;
+
+            this.Prerelease = prerelease ?? "";
+            this.Build = build ?? "";
+        }
+
+        /// 
+        /// Initializes a new instance of the  class.
+        /// 
+        /// The  that is used to initialize 
+        /// the Major, Minor, Patch and Build properties.
+        public SemVersion(Version version)
+        {
+            if (version == null)
+                throw new ArgumentNullException("version");
+
+            this.Major = version.Major;
+            this.Minor = version.Minor;
+
+            if (version.Revision >= 0)
+            {
+                this.Patch = version.Revision;
+            }
+
+            this.Prerelease = String.Empty;
+
+            if (version.Build > 0)
+            {
+                this.Build = version.Build.ToString();
+            }
+            else
+            {
+                this.Build = String.Empty;
+            }
+        }
+
+        /// 
+        /// Parses the specified string to a semantic version.
+        /// 
+        /// The version string.
+        /// If set to true minor and patch version are required, else they default to 0.
+        /// The SemVersion object.
+        /// When a invalid version string is passed.
+        public static SemVersion Parse(string version, bool strict = false)
+        {
+            var match = parseEx.Match(version);
+            if (!match.Success)
+                throw new ArgumentException("Invalid version.", "version");
+
+#if NETSTANDARD
+            var major = int.Parse(match.Groups["major"].Value);
+#else
+            var major = int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture);
+#endif
+
+            var minorMatch = match.Groups["minor"];
+            int minor = 0;
+            if (minorMatch.Success) 
+            {
+#if NETSTANDARD
+                minor = int.Parse(minorMatch.Value);
+#else
+                minor = int.Parse(minorMatch.Value, CultureInfo.InvariantCulture);
+#endif
+            }
+            else if (strict)
+            {
+                throw new InvalidOperationException("Invalid version (no minor version given in strict mode)");
+            }
+
+            var patchMatch = match.Groups["patch"];
+            int patch = 0;
+            if (patchMatch.Success)
+            {
+#if NETSTANDARD
+                patch = int.Parse(patchMatch.Value);
+#else
+                patch = int.Parse(patchMatch.Value, CultureInfo.InvariantCulture);
+#endif
+            }
+            else if (strict) 
+            {
+                throw new InvalidOperationException("Invalid version (no patch version given in strict mode)");
+            }
+
+            var prerelease = match.Groups["pre"].Value;
+            var build = match.Groups["build"].Value;
+
+            return new SemVersion(major, minor, patch, prerelease, build);
+        }
+
+        /// 
+        /// Parses the specified string to a semantic version.
+        /// 
+        /// The version string.
+        /// When the method returns, contains a SemVersion instance equivalent 
+        /// to the version string passed in, if the version string was valid, or null if the 
+        /// version string was not valid.
+        /// If set to true minor and patch version are required, else they default to 0.
+        /// False when a invalid version string is passed, otherwise true.
+        public static bool TryParse(string version, out SemVersion semver, bool strict = false)
+        {
+            try
+            {
+                semver = Parse(version, strict);
+                return true;
+            }
+            catch (Exception)
+            {
+                semver = null;
+                return false;
+            }
+        }
+
+        /// 
+        /// Tests the specified versions for equality.
+        /// 
+        /// The first version.
+        /// The second version.
+        /// If versionA is equal to versionB true, else false.
+        public static bool Equals(SemVersion versionA, SemVersion versionB)
+        {
+            if (ReferenceEquals(versionA, null))
+                return ReferenceEquals(versionB, null);
+            return versionA.Equals(versionB);
+        }
+
+        /// 
+        /// Compares the specified versions.
+        /// 
+        /// The version to compare to.
+        /// The version to compare against.
+        /// If versionA < versionB < 0, if versionA > versionB > 0,
+        /// if versionA is equal to versionB 0.
+        public static int Compare(SemVersion versionA, SemVersion versionB)
+        {
+            if (ReferenceEquals(versionA, null))
+                return ReferenceEquals(versionB, null) ? 0 : -1;
+            return versionA.CompareTo(versionB);
+        }
+
+        /// 
+        /// Make a copy of the current instance with optional altered fields. 
+        /// 
+        /// The major version.
+        /// The minor version.
+        /// The patch version.
+        /// The prerelease text.
+        /// The build text.
+        /// The new version object.
+        public SemVersion Change(int? major = null, int? minor = null, int? patch = null,
+            string prerelease = null, string build = null)
+        {
+            return new SemVersion(
+                major ?? this.Major,
+                minor ?? this.Minor,
+                patch ?? this.Patch,
+                prerelease ?? this.Prerelease,
+                build ?? this.Build);
+        }
+
+        /// 
+        /// Gets the major version.
+        /// 
+        /// 
+        /// The major version.
+        /// 
+        public int Major { get; private set; }
+
+        /// 
+        /// Gets the minor version.
+        /// 
+        /// 
+        /// The minor version.
+        /// 
+        public int Minor { get; private set; }
+
+        /// 
+        /// Gets the patch version.
+        /// 
+        /// 
+        /// The patch version.
+        /// 
+        public int Patch { get; private set; }
+
+        /// 
+        /// Gets the pre-release version.
+        /// 
+        /// 
+        /// The pre-release version.
+        /// 
+        public string Prerelease { get; private set; }
+
+        /// 
+        /// Gets the build version.
+        /// 
+        /// 
+        /// The build version.
+        /// 
+        public string Build { get; private set; }
+
+        /// 
+        /// Returns a  that represents this instance.
+        /// 
+        /// 
+        /// A  that represents this instance.
+        /// 
+        public override string ToString()
+        {
+            var version = "" + Major + "." + Minor + "." + Patch;
+            if (!String.IsNullOrEmpty(Prerelease))
+                version += "-" + Prerelease;
+            if (!String.IsNullOrEmpty(Build))
+                version += "+" + Build;
+            return version;
+        }
+
+        /// 
+        /// Compares the current instance with another object of the same type and returns an integer that indicates 
+        /// whether the current instance precedes, follows, or occurs in the same position in the sort order as the 
+        /// other object.
+        /// 
+        /// An object to compare with this instance.
+        /// 
+        /// A value that indicates the relative order of the objects being compared. 
+        /// The return value has these meanings: Value Meaning Less than zero 
+        ///  This instance precedes  in the sort order. 
+        ///  Zero This instance occurs in the same position in the sort order as . i
+        ///  Greater than zero This instance follows  in the sort order.
+        /// 
+        public int CompareTo(object obj)
+        {
+            return CompareTo((SemVersion)obj);
+        }
+
+        /// 
+        /// Compares the current instance with another object of the same type and returns an integer that indicates 
+        /// whether the current instance precedes, follows, or occurs in the same position in the sort order as the 
+        /// other object.
+        /// 
+        /// An object to compare with this instance.
+        /// 
+        /// A value that indicates the relative order of the objects being compared. 
+        /// The return value has these meanings: Value Meaning Less than zero 
+        ///  This instance precedes  in the sort order. 
+        ///  Zero This instance occurs in the same position in the sort order as . i
+        ///  Greater than zero This instance follows  in the sort order.
+        /// 
+        public int CompareTo(SemVersion other)
+        {
+            if (ReferenceEquals(other, null))
+                return 1;
+
+            var r = this.CompareByPrecedence(other);
+            if (r != 0)
+                return r;
+
+            r = CompareComponent(this.Build, other.Build);
+            return r;
+        }
+
+        /// 
+        /// Compares to semantic versions by precedence. This does the same as a Equals, but ignores the build information.
+        /// 
+        /// The semantic version.
+        /// true if the version precedence matches.
+        public bool PrecedenceMatches(SemVersion other)
+        {
+            return CompareByPrecedence(other) == 0;
+        }
+
+        /// 
+        /// Compares to semantic versions by precedence. This does the same as a Equals, but ignores the build information.
+        /// 
+        /// The semantic version.
+        /// 
+        /// A value that indicates the relative order of the objects being compared. 
+        /// The return value has these meanings: Value Meaning Less than zero 
+        ///  This instance precedes  in the version precedence.
+        ///  Zero This instance has the same precedence as . i
+        ///  Greater than zero This instance has creater precedence as .
+        /// 
+        public int CompareByPrecedence(SemVersion other)
+        {
+            if (ReferenceEquals(other, null))
+                return 1;
+
+            var r = this.Major.CompareTo(other.Major);
+            if (r != 0) return r;
+
+            r = this.Minor.CompareTo(other.Minor);
+            if (r != 0) return r;
+
+            r = this.Patch.CompareTo(other.Patch);
+            if (r != 0) return r;
+
+            r = CompareComponent(this.Prerelease, other.Prerelease, true);
+            return r;
+        }
+
+        static int CompareComponent(string a, string b, bool lower = false)
+        {
+            var aEmpty = String.IsNullOrEmpty(a);
+            var bEmpty = String.IsNullOrEmpty(b);
+            if (aEmpty && bEmpty)
+                return 0;
+
+            if (aEmpty)
+                return lower ? 1 : -1;
+            if (bEmpty)
+                return lower ? -1 : 1;
+
+            var aComps = a.Split('.');
+            var bComps = b.Split('.');
+
+            var minLen = Math.Min(aComps.Length, bComps.Length);
+            for (int i = 0; i < minLen; i++)
+            {
+                var ac = aComps[i];
+                var bc = bComps[i];
+                int anum, bnum;
+                var isanum = Int32.TryParse(ac, out anum);
+                var isbnum = Int32.TryParse(bc, out bnum);
+                int r;
+                if (isanum && isbnum)
+                {
+                    r = anum.CompareTo(bnum);
+                    if (r != 0) return anum.CompareTo(bnum);
+                }
+                else
+                {
+                    if (isanum)
+                        return -1;
+                    if (isbnum)
+                        return 1;
+                    r = String.CompareOrdinal(ac, bc);
+                    if (r != 0)
+                        return r;
+                }
+            }
+
+            return aComps.Length.CompareTo(bComps.Length);
+        }
+
+        /// 
+        /// Determines whether the specified  is equal to this instance.
+        /// 
+        /// The  to compare with this instance.
+        /// 
+        ///   true if the specified  is equal to this instance; otherwise, false.
+        /// 
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(obj, null))
+                return false;
+
+            if (ReferenceEquals(this, obj))
+                return true;
+
+            var other = (SemVersion)obj;
+
+            return this.Major == other.Major &&
+                this.Minor == other.Minor &&
+                this.Patch == other.Patch &&
+                string.Equals(this.Prerelease, other.Prerelease, StringComparison.Ordinal) &&
+                string.Equals(this.Build, other.Build, StringComparison.Ordinal);
+        }
+
+        /// 
+        /// Returns a hash code for this instance.
+        /// 
+        /// 
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// 
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int result = this.Major.GetHashCode();
+                result = result * 31 + this.Minor.GetHashCode();
+                result = result * 31 + this.Patch.GetHashCode();
+                result = result * 31 + this.Prerelease.GetHashCode();
+                result = result * 31 + this.Build.GetHashCode();
+                return result;
+            }
+        }
+
+#if !NETSTANDARD
+        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
+        public void GetObjectData(SerializationInfo info, StreamingContext context)
+        {
+            if (info == null) throw new ArgumentNullException("info");
+            info.AddValue("SemVersion", ToString());
+        }
+#endif
+
+        /// 
+        /// Implicit conversion from string to SemVersion.
+        /// 
+        /// The semantic version.
+        /// The SemVersion object.
+        public static implicit operator SemVersion(string version)
+        {
+            return SemVersion.Parse(version);
+        }
+
+        /// 
+        /// The override of the equals operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is equal to right true, else false.
+        public static bool operator ==(SemVersion left, SemVersion right)
+        {
+            return SemVersion.Equals(left, right);
+        }
+
+        /// 
+        /// The override of the un-equal operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is not equal to right true, else false.
+        public static bool operator !=(SemVersion left, SemVersion right)
+        {
+            return !SemVersion.Equals(left, right);
+        }
+
+        /// 
+        /// The override of the greater operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is greater than right true, else false.
+        public static bool operator >(SemVersion left, SemVersion right)
+        {
+            return SemVersion.Compare(left, right) > 0;
+        }
+
+        /// 
+        /// The override of the greater than or equal operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is greater than or equal to right true, else false.
+        public static bool operator >=(SemVersion left, SemVersion right)
+        {
+            return left == right || left > right;
+        }
+
+        /// 
+        /// The override of the less operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is less than right true, else false.
+        public static bool operator <(SemVersion left, SemVersion right)
+        {
+            return SemVersion.Compare(left, right) < 0;
+        }
+
+        /// 
+        /// The override of the less than or equal operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is less than or equal to right true, else false.
+        public static bool operator <=(SemVersion left, SemVersion right)
+        {
+            return left == right || left < right;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Editor/SemVersion.cs.meta b/Editor/SemVersion.cs.meta
new file mode 100644
index 0000000..bb4a6b8
--- /dev/null
+++ b/Editor/SemVersion.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f3aaa6a7a403b4f7ca7c0c0822f60984
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Editor/Utils.cs b/Editor/Utils.cs
new file mode 100644
index 0000000..fb13079
--- /dev/null
+++ b/Editor/Utils.cs
@@ -0,0 +1,89 @@
+using System.IO;
+using System.Text;
+using UnityEditor;
+using UnityEngine;
+
+namespace Coffee.PackageManager
+{
+	internal static class GitUtils
+	{
+		static readonly StringBuilder s_sbError = new StringBuilder ();
+		static readonly StringBuilder s_sbOutput = new StringBuilder ();
+
+		public static bool IsGitRunning { get; private set; }
+
+		public delegate void GitCommandCallback (bool success, string output);
+
+		public static bool ClonePackage (PackageMeta pi)
+		{
+			var outpath = "Packages/." + pi.name;
+			if (Directory.Exists (outpath))
+			{
+				FileUtil.DeleteFileOrDirectory (outpath);
+			}
+
+			string args = string.Format ("clone --depth=1 --branch {0} --single-branch {1} {2}", pi.branch, pi.path, outpath);
+			ExecuteGitCommand (args,
+			(success, _) =>
+			{
+				if (success)
+				{
+					FileUtil.DeleteFileOrDirectory (outpath + "/.git");
+				}
+			},
+			true);
+
+			return Directory.Exists (outpath);
+		}
+
+		static WaitWhile ExecuteGitCommand (string args, GitCommandCallback callback, bool waitForExit = false)
+		{
+			var startInfo = new System.Diagnostics.ProcessStartInfo
+			{
+				Arguments = args,
+				CreateNoWindow = true,
+				FileName = "git",
+				RedirectStandardError = true,
+				RedirectStandardOutput = true,
+				UseShellExecute = false,
+			};
+
+			var launchProcess = System.Diagnostics.Process.Start (startInfo);
+			if (launchProcess == null || launchProcess.HasExited == true || launchProcess.Id == 0)
+			{
+				Debug.LogError ("No 'git' executable was found. Please install Git on your system and restart Unity");
+				callback (false, "");
+			}
+			else
+			{
+				//Add process callback.
+				IsGitRunning = true;
+				s_sbError.Length = 0;
+				s_sbOutput.Length = 0;
+				launchProcess.OutputDataReceived += (sender, e) => s_sbOutput.AppendLine (e.Data ?? "");
+				launchProcess.ErrorDataReceived += (sender, e) => s_sbError.AppendLine (e.Data ?? "");
+				launchProcess.Exited += (sender, e) =>
+				{
+					IsGitRunning = false;
+					bool success = 0 == launchProcess.ExitCode;
+					if (!success)
+					{
+						Debug.LogErrorFormat ("Error: git {0}\n\n{1}", args, s_sbError);
+					}
+					callback (success, s_sbOutput.ToString ());
+				};
+
+				launchProcess.BeginOutputReadLine ();
+				launchProcess.BeginErrorReadLine ();
+				launchProcess.EnableRaisingEvents = true;
+
+				if (waitForExit)
+				{
+					launchProcess.WaitForExit ();
+				}
+			}
+
+			return new WaitWhile (() => IsGitRunning);
+		}
+	}
+}
diff --git a/Editor/Utils.cs.meta b/Editor/Utils.cs.meta
new file mode 100644
index 0000000..4864ec7
--- /dev/null
+++ b/Editor/Utils.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5b938f54b26d24ad08f40d5c288dafcd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100755
index 0000000..a65ed40
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,7 @@
+Copyright 2019 mob-sakai
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/LICENSE.md.meta b/LICENSE.md.meta
new file mode 100755
index 0000000..aeb7d81
--- /dev/null
+++ b/LICENSE.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5d62a8df4b1a6428a8f8a40fe77eee37
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/README.md b/README.md
new file mode 100755
index 0000000..234ba85
--- /dev/null
+++ b/README.md
@@ -0,0 +1,154 @@
+Git Dependency Resolver For Unity
+===
+
+This plugin resolves git url dependencies in the package for Unity Package Manager.  
+You can use a git url as a package dependency!
+
+![logo](https://user-images.githubusercontent.com/12690315/57779067-636a7e00-7760-11e9-8f4a-06bbaee402e8.png)
+
+[![](https://img.shields.io/github/release/mob-sakai/GitDependencyResolverForUnity.svg?label=latest%20version)](https://github.com/mob-sakai/GitDependencyResolverForUnity/releases)
+[![](https://img.shields.io/github/release-date/mob-sakai/GitDependencyResolverForUnity.svg)](https://github.com/mob-sakai/GitDependencyResolverForUnity/releases)
+![](https://img.shields.io/badge/unity-2017%2B-green.svg)
+[![](https://img.shields.io/github/license/mob-sakai/GitDependencyResolverForUnity.svg)](https://github.com/mob-sakai/GitDependencyResolverForUnity/blob/upm/LICENSE.txt)
+[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-orange.svg)](http://makeapullrequest.com)
+[![](https://img.shields.io/twitter/follow/mob_sakai.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=mob_sakai)
+
+<< [Description](#Description) | [Install](#install) | [Usage](#usage) | [Development Note](#development-note) >>
+
+### What's new? [See changelog ![](https://img.shields.io/github/release-date/mob-sakai/GitDependencyResolverForUnity.svg?label=last%20updated)](https://github.com/mob-sakai/GitDependencyResolverForUnity/blob/upm/CHANGELOG.md)
+### Do you want to receive notifications for new releases? [Watch this repo ![](https://img.shields.io/github/watchers/mob-sakai/GitDependencyResolverForUnity.svg?style=social&label=Watch)](https://github.com/mob-sakai/GitDependencyResolverForUnity/subscription)
+### Support me on Patreon! [![become_a_patron](https://user-images.githubusercontent.com/12690315/50731629-3b18b480-11ad-11e9-8fad-4b13f27969c1.png)](https://www.patreon.com/join/2343451?)
+
+
+
+



+## Description + +In Unity 2018.3, the Unity Package Manager (UPM) supported Git. :) +https://forum.unity.com/threads/git-support-on-package-manager.573673/ + +This update allows us to quickly install packages on code hosting services such as GitHub. + +However, UPM does not support git urls as dependencies in the package. :( + +``` +[ package-a/package.json ] +{ + "name": "com.coffee.package-a", + "version": "0.3.0", + "dependencies": { + "com.coffee.core-a" : "https://github.com/mob-sakai/GitPackageTest#core-a-0.1.0" + } +} + +==== +An error occurred while resolving packages: + Package com.coffee.package-a@https://github.com/mob-sakai/GitPackageTest#package-a-0.3.0 has invalid dependencies: + com.coffee.core-a: Version 'https://github.com/mob-sakai/GitPackageTest#core-a-0.1.0' is invalid. Expected a 'SemVer' compatible value. + +A re-import of the project may be required to fix the issue or a manual modification of *****/Packages/manifest.json file. +``` + +
+This plugin resolves git url dependencies in the package for Unity Package Manager. + +You can use a git url as a package dependency! + + +#### Features + +* Easy to use: just install +* Resolve git url dependencies in packages +* Uninstall unused packages that is installed by this plugin +* Support GitHub, Bitbucket, GitLab, etc. +* Support private repository +* Support Unity 2019.1+ +* Support .Net 3.5 & 4.x +* Update package with a specific tag/branch + + + +



+## Install + +Find `Packages/manifest.json` in your project and edit it to look like this: +```js +{ + "dependencies": { + "com.coffee.git-dependency-resolver": "https://github.com/mob-sakai/GitDependencyResolverForUnity.git#1.0.0", + ... + }, +} +``` +To update the package, change `#{version}` to the target version. +Or, use [UpmGitExtension](https://github.com/mob-sakai/UpmGitExtension.git). + + +##### Requirement + +* Unity 2018.3+ *(including 2019.1+)* + + + +



+## Usage + +* If dependencies are not resolved successfully, try the following: + * Reopen the project. + * Delete `Library` directory in the project. +![library](https://user-images.githubusercontent.com/12690315/57823863-06a8ab00-77d4-11e9-95ce-d92220bf716f.png) +* When `Unity Package Manager Error` window is opens, click `Continue`. +![window](https://user-images.githubusercontent.com/12690315/57823865-08726e80-77d4-11e9-8203-46bf22d504d9.png) +* Use [SemVer](https://semver.org/) as a tag or branch name. +eg. `1.0.0`, `0.5.0-preview10`, `0.1.0-alpha+daily5` + + + +



+## Development Note + +#### Develop a package for UPM + +The branching strategy when I develop a package for UPM is as follows. + +|Branch|Description|'Assets' directory| +|-|-|-| +|develop|Development, Testing|Included| +|upm(default)|Subtree to publish for UPM|Excluded| +|{tags}|Tags to install using UPM|Excluded| + +**Steps to release a package:** +1. Develop your package project on `develop` branch and update version in `package.json`. +2. Split subtree into `ump` branch. +`git subtree split --prefix=Assets/YOUR/PACKAGE/DIRECTRY --branch upm` +3. Tag on `ump` branch as new version. +4. That's all. :) + +For details, see https://www.patreon.com/posts/25070968. + + + +



+## License + +* MIT +* [MiniJson](https://gist.github.com/darktable/1411710) by Calvin Rien +* [SemVer](https://github.com/maxhauser/semver) by Max Hauser + + + +## Author + +[mob-sakai](https://github.com/mob-sakai) +[![](https://img.shields.io/twitter/follow/mob_sakai.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=mob_sakai) +[![become_a_patron](https://user-images.githubusercontent.com/12690315/50731615-ce9db580-11ac-11e9-964f-e0423533dc69.png)](https://www.patreon.com/join/2343451?) + + + +## See Also + +* GitHub page : https://github.com/mob-sakai/GitDependencyResolverForUnity +* Releases : https://github.com/mob-sakai/GitDependencyResolverForUnity/releases +* Issue tracker : https://github.com/mob-sakai/GitDependencyResolverForUnity/issues +* Current project : https://github.com/mob-sakai/GitDependencyResolverForUnity/projects/1 +* Change log : https://github.com/mob-sakai/GitDependencyResolverForUnity/blob/upm/CHANGELOG.md diff --git a/README.md.meta b/README.md.meta new file mode 100755 index 0000000..8fc64fb --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 09f782862c8e14f85802b6589e507711 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json new file mode 100755 index 0000000..7b7ed3d --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "com.coffee.git-dependency-resolver", + "displayName": "Git Dependency Resolver", + "description": "This plugin resolves git dependencies in the package for Unity Package Manager.\nYou can use a git url as a package dependency!", + "version": "1.0.0", + "unity": "2018.3", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/mob-sakai/GitDependencyResolverForUnity.git" + }, + "src": "Assets/GitDependencyResolver", + "author": "mob-sakai (https://github.com/mob-sakai)", + "dependencies": { + } +} diff --git a/package.json.meta b/package.json.meta new file mode 100755 index 0000000..1ddd23d --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b0bf7fb91a9a24c6c8e4cd5a550914ea +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: