xp-runners / reference

Reference implementation in C#
Other
0 stars 1 forks source link

.env #87

Open thekid opened 12 months ago

thekid commented 12 months ago

Support .env files containing environment variables:

$ cat .env
KEY=value

$ xp -env .env -w '$_ENV["KEY"]'
value

Automatically reading

NodeJS and Deno require explicit command line arguments, while Bun reads the following files automatically:

See also

thekid commented 2 months ago

POC implementation (mis-)using the Ini parser:

diff --git a/src/xp.runner.test/CommandLineTest.cs b/src/xp.runner.test/CommandLineTest.cs
index 77780ac..4822ac5 100755
--- a/src/xp.runner.test/CommandLineTest.cs
+++ b/src/xp.runner.test/CommandLineTest.cs
@@ -225,6 +225,30 @@ namespace Xp.Runners.Test
             );
         }

+        [Fact]
+        public void env_initially_empty()
+        {
+            Assert.Equal(new Ini[] { }, new CommandLine(new string[] { }).EnvFiles.ToArray());
+        }
+
+        [Fact]
+        public void one_environment_entry()
+        {
+            Assert.Equal(
+                new Ini[] { new Ini(".env") },
+                new CommandLine(new string[] { "-env", ".env" }).EnvFiles.ToArray()
+            );
+        }
+
+        [Fact]
+        public void multiple_environment_entries()
+        {
+            Assert.Equal(
+                new Ini[] { new Ini(".env"), new Ini(".env.prod") },
+                new CommandLine(new string[] { "-env", ".env", "-env", ".env.prod" }).EnvFiles.ToArray()
+            );
+        }
+
         [Fact]
         public void runonce_is_default_execution_model()
         {
diff --git a/src/xp.runner/Command.cs b/src/xp.runner/Command.cs
index 319cb9d..153ef3b 100755
--- a/src/xp.runner/Command.cs
+++ b/src/xp.runner/Command.cs
@@ -116,10 +116,17 @@ namespace Xp.Runners
             );

             var env = proc.StartInfo.EnvironmentVariables;
-            env["XP_EXE"]= binary;
-            env["XP_VERSION"]= Assembly.GetExecutingAssembly().GetName().Version.ToString();
-            env["XP_MODEL"]= cmd.ExecutionModel.Name;
-            env["XP_COMMAND"]= GetType().Name.ToLower();
+            env["XP_EXE"] = binary;
+            env["XP_VERSION"] = Assembly.GetExecutingAssembly().GetName().Version.ToString();
+            env["XP_MODEL"] = cmd.ExecutionModel.Name;
+            env["XP_COMMAND"] = GetType().Name.ToLower();
+            foreach (var config in cmd.EnvFiles)
+            {
+                foreach (var key in config.Keys("default"))
+                {
+                    env[key] = config.Get("default", key).Trim('"');
+                }
+            }

             return cmd.ExecutionModel.Execute(proc, encoding);
         }
diff --git a/src/xp.runner/CommandLine.cs b/src/xp.runner/CommandLine.cs
index 554e863..23422e2 100755
--- a/src/xp.runner/CommandLine.cs
+++ b/src/xp.runner/CommandLine.cs
@@ -28,6 +28,7 @@ namespace Xp.Runners
             { "-cp?", (self, value) => self.path["classpath"].Add("?" + value) },
             { "-cp!", (self, value) => self.path["classpath"].Add("!" + value) },
             { "-m", (self, value) => self.path["modules"].Add(value) },
+            { "-env", (self, value) => self.envFiles.Add(new Ini(value)) },
             { "-watch", (self, value) => self.executionModel = new RunWatching(value) },
             { "-repeat", (self, value) => self.executionModel = new RunRepeatedly(value) },
             { "-c", (self, value) => self.config = new CompositeConfigSource(
@@ -45,9 +46,10 @@ namespace Xp.Runners
         private Dictionary<string, List<string>> path = new Dictionary<string, List<string>>()
         {
             { "classpath", new List<string>() },
-            { "modules", new List<string>() }
+            { "modules", new List<string>() },
         };

+        private List<Ini> envFiles = new List<Ini>();
         private Command command;
         private IEnumerable<string> arguments;
         private ExecutionModel executionModel;
@@ -59,6 +61,12 @@ namespace Xp.Runners
             get { return path; }
         }

+        /// <summary>.env files</summary>
+        public List<Ini> EnvFiles
+        {
+            get { return envFiles; }
+        }
+
         /// <summary>Subcommand name</summary>
         public Command Command
         {
diff --git a/src/xp.runner/config/Ini.cs b/src/xp.runner/config/Ini.cs
index d4b69a5..72c3700 100644
--- a/src/xp.runner/config/Ini.cs
+++ b/src/xp.runner/config/Ini.cs
@@ -6,7 +6,7 @@ using System.Linq;

 namespace Xp.Runners.Config
 {
-    class Ini
+    public class Ini
     {
         private static char[] SEPARATOR = new char[] { '=' };

@@ -97,5 +97,17 @@ namespace Xp.Runners.Config
             if (!sections.ContainsKey(section)) return defaultValue;
             return sections[section].Keys;
         }
+
+        /// <summary>Tests for equality</summary>
+        public override bool Equals(Object obj)
+        {
+            return obj is Ini && ((Ini) obj).file == this.file;
+        }
+
+        /// <summary>Hashcode implementation</summary>
+        public override int GetHashCode()
+        {
+            return this.file.GetHashCode();
+        }
     }
 }
\ No newline at end of file