bitwalker / exrm Goto Github PK
View Code? Open in Web Editor NEWAutomatically generate a release for your Elixir project!
License: MIT License
Automatically generate a release for your Elixir project!
License: MIT License
If {app}.conf
does not exist under config/
it is created from config/config.exs
when running mix release
.
If it does exist, though, and changes are made to the config.exs
file, building a new release will not update the {app}.conf
, and the changes will not be reflected in the build.
I want to set some custom settings in app.conf
and vm.args
, but I can't find any space to place it. Is exrm
support custom app.conf
and vm.args
, and copy them to the release directory? Thanks.
I don't know why, but it occurred. I add poolboy as my dependence, use your tool to create a release, I found it can't add poolboy
as it's dependence. You can try it.
Hi,
when trying to create a release as follows:
mix release --erl="-config config/app.config" --dev
I get the following error:
Dependency unicode is specified as a dependency but is not reachable by the system.
I don't really know from which dependency this comes from (I suppose hackney_lib, but not sure) but it would be nice to have a better error message, specifying where exactly this problem came up (if possible..).
And the second thing is: I think the "unicode" dependency is an erlang module, therefore it should be found, IMHO.
relx doesn't, in its present state as used by exrm, seem to run on Windows. Therefore releases can't be produced on that platform.
I'm getting the following error on release built on 0.13.2 and exrm 0.6.10
[root@ucx50-4 mdse]# tar xzf ../mdse-0.1.0.tar.gz
[root@ucx50-4 mdse]# bin/mdse start
** (Code.LoadError) could not load /tmp/mdse/releases/0.1.0/mdse.schema.exs
(elixir) lib/code.ex:473: Code.find_file/2
(elixir) lib/code.ex:254: Code.eval_file/2
(conform) lib/conform_schema.ex:16: Conform.Schema.load/1
(conform) lib/conform.ex:75: Conform.process/1
(elixir) lib/kernel/cli.ex:39: Kernel.CLI.run/2
(stdlib) escript.erl:752: :escript.run/2
(stdlib) escript.erl:276: :escript.start/1
:init.start_it/1
[root@ucx50-4 mdse]# ls releases/0.1.0/
mdse.rel start.boot sys.config vm.args
[root@ucx50-4 mdse]#
I'd love to be able to build purely erlang projects using mix
and exrm
. A stepping stone to this is being able to configure a release to exclude the elixir/iex runtime.
Example project with first steps to a working mix.exs
for compiling and building release here: https://github.com/sanmiguel/rest_service/tree/r17-maps-mix
There's only test.boot
in releases/0.0.2
dir but start.boot
required.
ERROR: release_handler:check_install_release failed: {no_such_file, "/tmp/exrm/test/0.0.2/start.boot"}
PS. [ { :exrm, "~> 0.14.2" } ]
Using the latest version of exrm
(v0.10.0) and the current elixir master (v0.14.2-dev), running mix release
generates an error. I tried a deps.clean
and deps.update
. I traced it back to the mix escriptize
command in a hidden conform
task called by exrm
. I have an empty config.exs
file that generated default conf
and schema
files.
Stacktrace:
$ mix release
==> Generating sys.config...
==> Generating boot script...
==> Conform: Checking for ex_m3.schema.exs...
==> Conform: Checking for ex_m3.conf...
==> Conform: Generating escript..
==> Conform: Adding overlays to relx.config
==> Failed to execute before_release hook for Elixir.ReleaseManager.Plugin.Conform!
** (FunctionClauseError) no function clause matching in String.to_char_list/1
(elixir) lib/string.ex:1249: String.to_char_list({:error, "Failed to generate escript."})
lib/exrm/plugins/conform.ex:37: anonymous fn/7 in ReleaseManager.Plugin.Conform.before_release/1
(elixir) lib/enum.ex:1252: Enum."-reduce/3-lists^foldl/2-0-"/3
lib/exrm/plugins/conform.ex:33: ReleaseManager.Plugin.Conform.before_release/1
lib/mix/tasks/release.ex:198: anonymous fn/2 in Mix.Tasks.Release.execute_before_hooks/1
(elixir) lib/enum.ex:1252: Enum."-reduce/3-lists^foldl/2-0-"/3
lib/mix/tasks/release.ex:65: Mix.Tasks.Release.do_run/1
(mix) lib/mix/cli.ex:66: Mix.CLI.run_task/2
I have to edit the release script for my app.
I have two issues here. After cloning my project on a new machine, the first mix release failed. I did not notice the error, copies the tar file to the target system, installed it but it did not work.
[root@localhost exrm_test3]# bin/exrm_test3 start
escript: Failed to open file: /tmp/exrm_test3/bin/conform
After reviewing this error on the build:
[root@ucx50 exrm_test3]# mix release
==> Generating sys.config...
==> Generating boot script...
==> Conform: Checking for exrm_test3.schema.exs...
==> Conform: Checking for exrm_test3.conf...
==> Conform: Generating escript..
==> Failed to execute before_release hook for Elixir.ReleaseManager.Plugin.Conform!
==> Generating release...
==> Generating nodetool...
==> Your release is ready!
I ran mix release
again. This time it worked. Installing the new release tar file on the target system worked.
My concerns:
mix release
fail, while running it again worked?Hi,
I've build the project on my mac running 'mix release', I copied the tar.gz file into our test server on Amazon, running linux 14.04.
While trying to run it I get this message:
erts-6.0/bin/escript: 1: erts-6.0/bin/escript: Syntax error: "(" unexpected
We used this server previously to run the project successfully, build on linux running 'mix release'.
Please advice,
Ariel
Hi, I've started tinkering with Elixir a little and stumbled across your project. It's a really nice tool, great work!
I couldn't find any information on whether it supported Mix-style "umbrella" projects. Can I call mix release
at the toplevel and get many apps bundled together into a release?
Currently fails with :enoent on boot.
instead of my_app/bin/conform we should have my_app/releases/0.0.1/conform
the reasoning is that the conform executable is directly related to the specific schema and conf format used in that release. over the lifetime of an app, if the version of conform changes in a way that is not backwards compatible then using the older binary will cause issues. For this reason the conform executable should instead be located with the associated schema and conf files within the appropriate releases subdirectory
I believe it would be nice have the ability to add help in plugins. I'm not sure how difficult it would be to do with the built in help since its handled automatically by reading the comments of the task.
Perhaps we could add a --help to mix release that would display the help comments of each installed plugin. I know there is an API to get to the @doc so I presume this latter approach should be fairly straight forward to implement.
Your thoughts?
Elixir 0.13.2 and exrm 0.6.11, centos without erlang.
[root@ucx50-4 exrm_test3]# bin/exrm_test3 start
bin/exrm_test3: line 67: erts-6.0/bin/escript: cannot execute binary file
[root@ucx50-4 exrm_test3]# ls releases/0.0.1/
exrm_test3.boot exrm_test3.conf exrm_test3.rel exrm_test3.schema.exs exrm_test3.script sys.config vm.args
[root@ucx50-4 exrm_test3]#
Test project release built with
Erlang 17.0
Elixir 0.13.2
Exrm 0.6.3
I installed the release on system which it was build and had no issues with start, ping, stop
Installed test release on target centos system WITHOUT elixir or erlang installed.
[root@ucx50-4 test]# bin/test start
bin/test: line 130: /usr/local/test/erts-6.0/bin/run_erl: cannot execute binary file
[root@ucx50-4 test]#
What's interesting, is that I have a release of another application install on the same target. This release was built with Elixir 0.13.1 and exrm 0.5.0. This release starts and pings file. However, bin/mdse remote_console returns the following error.
[root@ucx50-4 mdse]# bin/mdse remote_console
bin/mdse: line 212: exec: iex: not found
[root@ucx50-4 mdse]#
I was able to get the example working on my MAC. However, I can't get it running on my Linux machine Centos 5.6
Building the release:
# mix release
==> Generating boot script...
==> Generating release...
===> Missing beam file dialyzer_gui <<"/usr/local/lib/erlang/lib/dialyzer-2.7/ebin/dialyzer_gui.beam">>
===> Missing beam file megaco_ber_encoder <<"/usr/local/lib/erlang/lib/megaco-3.17.1/ebin/megaco_ber_encoder.beam">>
rlx_mkdir_template_10060061_1778763: Warning: Compiled template not saved (need out_dir option)
rlx_copy_from_template_27204117_392716: Warning: Compiled template not saved (need out_dir option)
rlx_copy_to_template_95229086_953347: Warning: Compiled template not saved (need out_dir option)
rlx_copy_from_template_3751675_5615814: Warning: Compiled template not saved (need out_dir option)
rlx_copy_to_template_95947454_6232508: Warning: Compiled template not saved (need out_dir option)
==> Your release is ready!
#
Installed to /tmp/test
[root@ucx50 test]# bin/test start
[root@ucx50 test]# bin/test ping
{"init terminating in do_boot",{'cannot load',error_handler,get_files}}
Crash dump was written to: erl_crash.dump
init terminating in do_boot ()
[root@ucx50 test]# bin/test remote_console
Crash dump was written to: erl_crash.dump
init terminating in do_boot ()
[root@ucx50 test]# bin/test start
[root@ucx50 test]# bin/test remote_console
Crash dump was written to: erl_crash.dump
init terminating in do_boot ()
Any ideas?
in earlier versions of exrm it worked just fine
do you have any ideas how to fix it?
I just came across this project on hex.pm and noticed you are calling relx
from a shell process. It'd be better in this case to use the relx
API, like how the rebar
plugin does: https://github.com/erlware/relx/blob/master/src/relx.erl#L87
A couple things need to happen before this feature is complete:
relx.config
file needs to be updated to reflect each new release*.appup
configuration, which describes how applications are upgraded/downgraded.*.relup
configuration, which describes how releases are upgraded/downgraded.calls to eldap are missing some of the dependancies:
See https://github.com/bitwalker/conform for more info.
Scheduled for the next major release of exrm
I would like to add clean support to my plugin. Having a clean hook would be the best way to accomplish this.
If you don't mind, I'd like to implement this and send you a pull request. I'm thinking a single hook run after the main clean. I propose after_clean(args).
What do you think?
Hi,
I generated a release using mix release --dev
:
==> Generating relx configuration...
==> Generating sys.config...
==> Generating boot script...
==> Performing protocol consolidation...
==> Conform: Loading schema...
==> amnesia
warning: the dependency amnesia requires Elixir "~> 0.14.4-dev" but you are running on v0.14.1
==> apex
warning: the dependency apex requires Elixir "~> 0.14.2" but you are running on v0.14.1
==> timex
warning: the dependency timex requires Elixir "~> 0.14.3" but you are running on v0.14.1
==> exrm
warning: the dependency exrm requires Elixir "~> 0.14.3" but you are running on v0.14.1
==> conform
warning: the dependency conform requires Elixir "~> 0.14.3" but you are running on v0.14.1
==> Conform: No schema found, conform will not be packaged in this release!
==> Generating release...
===> Application metadata file exists but is malformed: ~/.exenv/versions/0.14.1/lib/mix/test/fixtures/deps_status/_build/dev/lib/invalidapp/ebin/invalidapp.app
===> Application metadata file exists but is malformed: ~/.exenv/versions/0.14.1/lib/mix/test/fixtures/deps_status/_build/dev/lib/invalidvsn/ebin/invalidvsn.app
===> Application metadata file exists but is malformed: ~/.exenv/versions/0.14.1/lib/mix/test/fixtures/deps_status/_build/dev/lib/ok/ebin/ok.app
==> Generating nodetool...
==> Packaging release...
==> The release for server-0.0.1 is ready!
After that I wanted to start it using console
:
$ rel/server/bin/server console
Exec: ~/server/rel/server/erts-6.0/bin/erlexec -boot ~/server/rel/server/releases/0.0.1/server -env ERL_LIBS ~/server/rel/server/lib -config ~/server/rel/server/releases/0.0.1/sys.config -pa ~/server/rel/server/lib/consolidated -args_file ~/server/rel/server/releases/0.0.1/vm.args -user Elixir.IEx.CLI -extra --no-halt +iex -- console
Root: ~/server/rel/server
~/server/rel/server
Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
=INFO REPORT==== 29-Jul-2014::06:55:07 ===
application: ranch
exited: {bad_return,
{{ranch_app,start,[normal,[]]},
{'EXIT',
{undef,
[{ranch_app,start,[normal,[]],[]},
{application_master,start_it_old,4,
[{file,"application_master.erl"},
{line,272}]}]}}}}
type: permanent
{"Kernel pid terminated",application_controller,"{application_start_failure,ranch,{bad_return,{{ranch_app,start,[normal,[]]},{'EXIT',{undef,[{ranch_app,start,[normal,[]],[]},{application_master,start_it_old,4,[{file,\"application_master.erl\"},{line,272}]}]}}}}}"}
Crash dump was written to: erl_crash.dump
Kernel pid terminated (application_controller) ({application_start_failure,ranch,{bad_return,{{ranch_app,start,[normal,[]]},{'EXIT',{undef,[{ranch_app,start,[normal,[]],[]},{application_master,start
When trying to use start
it just exits immediately :|
Do you have an idea what's going on?
The time has come to say goodbye to our good friend relx. Relx has been fantastic for exrm so far, but ultimately if we want to make exrm as powerful a tool as possible, we're going to need to take over control of the process. Additionally, if this is ever to become a project under the @elixir-lang umbrella, it will need to be dependency-free, and written in Elixir in it's entirety.
So the general steps are as follows:
lib_dirs
}:applications
.There are things not listed here which will need to be built, so as I run into them I'll add them to the list here. Feedback on current features or new features is absolutely welcome, so feel free to chime in if you have wants/needs/beef, whatever.
In addition to the production environment, we have two integration/staging environments for which we would like to build releases for as well.
Is there a reason, that prod is hard coded and it's not checking, lets say the MIX_ENV variable?
If not, would you accept a pull request for that?
Currently unit tests are...inadequate. I'd like to add tests for as much functionality as possible to prevent regressions as more and more complexity is added. It will be especially important once the extraction of relx begins, and the need for verification of the new implementation becomes a necessity. Some ideas for tests:
I've updated the exrm-umbrella-test
so that I could put together a reproducible case of this bug for you. My PR is available here:
bitwalker/distillery-umbrella-test#1
If you run this project with mix release
you'll see the following error message:
==> Failed to execute before_release hook for Elixir.ReleaseManager.Plugin.Conform!
** (Mix) [app_one] Unknown dependency conform for environment dev
The applications do not make use of conform
it appears that the dependency belongs to exrm
itself. Let me know if I can help with debugging the problem further.
cc @smpallen99
This is scheduled for the next major release of exrm.
I had an older project that I tried upgrading to 0.6.7. The project did not have a config directory. Should mix release really fail?
➜ exrm-test git:(master) ✗ mix release
==> Generating sys.config...
==> Generating boot script...
==> Conform: Checking for extest.schema.exs...
==> Conform: No schema found, generating one at config/extest.schema.exs
** (File.Error) could not write to file /Users/spallen/myprojects/elixir/exrm-test/config/extest.schema.exs: no such file or directory
(elixir) lib/file.ex:740: File.write!/3
lib/mix/tasks/conform.new.ex:30: Mix.Tasks.Conform.New.run/1
lib/exrm/plugins/conform.ex:17: ReleaseManager.Plugin.Conform.run/1
lib/mix/tasks/release.ex:174: anonymous fn/2 in Mix.Tasks.Release.execute_plugins/1
(elixir) lib/enum.ex:1252: Enum."-reduce/3-lists^foldl/2-0-"/3
lib/mix/tasks/release.ex:53: Mix.Tasks.Release.run/1
(mix) lib/mix/cli.ex:66: Mix.CLI.run_task/2
./configure && make
lib
in /usr/local/elixir/lib
and bin
in /usr/local/bin
.mix release
fails saying it cannot resolve the snmp
application, even though the logs show that it was able to resolve it.Maybe I don't understand how this works, but if I untar the release on another machine, I can start my application but I get undef
when I make calls to Poison.encode!
Poking around in the release direction, there is not poison dir under /lib
Am I doing something wrong here?
If you have a "library" that is not really an application that need to get started, you need to put it on applications
on mix.exs file to be part of the release.
I don't think this should not be necessary. Am I doing something wrong?
I have exrm
added as follows:
{:exrm, "~> 0.11.1", only: :rel}
Then I run
$ MIX_ENV=rel mix release
The first time it runs, it creates .conf
and .schema.exs
files.
I have set up my config.exs
to import config for the currently set environment:
use Mix.Config
cfg = Path.expand("#{Mix.env}.exs", __DIR__)
if File.exists?(cfg) do
import_config cfg
end
I only have a file for the dev environment – dev.exs
:
use Mix.Config
config :muweb, dbg_log_enabled: true
and that's it.
This is the .conf
file I end up with after the release is built:
# Documentation for muweb.dbg_log_enabled goes here.
muweb.dbg_log_enabled = true
So it appears that it used dev.exs
to populate the .conf
file.
Running into this issue:
$ mix release
==> Generating relx configuration...
** (FunctionClauseError) no function clause matching in Keyword.get/3
(elixir) lib/keyword.ex:118: Keyword.get(Mix.Project.Config, :deps_path, nil)
lib/mix/tasks/release.ex:115: Mix.Tasks.Release.generate_relx_config/1
lib/mix/tasks/release.ex:64: Mix.Tasks.Release.do_run/1
(mix) lib/mix/project.ex:184: Mix.Project.in_project/4
(elixir) lib/file.ex:1045: File.cd!/2
lib/mix/tasks/release.ex:49: Mix.Tasks.Release."-run/1-lc$^0/1-0-"/3
(mix) lib/mix/cli.ex:63: Mix.CLI.run_task/2
Looking at the code here https://github.com/bitwalker/exrm/blob/master/lib/mix/tasks/release.ex#L115 I'm wondering if it's not caused by a typo? L111 just above that has Mix.Project.config
with lowercase "c".
This is a bug in Elixir that I have a pull request in for, where the standard core dependencies :kernel
, :stdlib
, and :elixir
aren't included in the generated .app file. This causes applications that have no dependencies to not be included in the final release, and cause your release to fail.
I'll update this issue when my PR has been merged.
So today, my approach to the boot script is pretty much "don't touch it". For the conform integration though, I had to add in my own custom hooks in order to handle the runtime functionality that conform requires. That situation was a bit of a one-time deal just for exrm, but I assume that folks who wish to write plugins for exrm will potentially need to execute code at runtime like conform does. This issue is to start discussion around how the boot script can be re-architected so that behavior like that can be sourced in when the release is built. The boot script is written in sh
(and batch for windows support), so we'll need to maintain that. My shell scripting skills are good enough to maintain and add features to the boot script today, but I'm not sure on what the best approach is to implement something like this. I guess I haven't heard or encountered pluggable shell scripts before, so I'm not sure if it's even possible. Here's what I'd like to see though:
rel
└── app
└── bin
├── app
├── app.bat
└── boot_plugins
├── conform
├── conform.bat
└── exrm_rpm
So basically, plugins will declare an attribute, @boot
, which can be declared multiple times (it will accumulate), containing a path to a shell script in the plugin's project which contains the plugin's behavior for the boot script. This attribute is optional. In addition, plugins will have a new callback, is_active?
, which will be given a config struct, and must return a boolean indicating whether that plugin is active for this release. When the release is built, it will get all @boot
paths for plugins where is_active?
returns true, and copy them to the output bin directory. When running rel/app/bin/app
, the boot script, app
or app.bat
in this example, will source in all scripts in boot_plugins
(either the shell version, or the batch version, depending on platform). The hope is that we can have a well defined way to define plugin scripts, such that sourcing them in ensures that the plugins will get executed at predefined times. We could maybe pass in the current boot type (foreground, console, start/stop, etc.), and let the plugins decide what to do for each type. We should probably also allow scripts to set up their own boot tasks (such as a plugin which defines a "special-console" task or something).
Thoughts?
/cc @alco @smpallen99
Compiled lib/exrm/config.ex
Compiled lib/exrm/plugin.ex
Compiled lib/exrm/utils.ex
Compiled lib/mix/tasks/release.clean.ex
== Compilation error on file lib/mix/tasks/release.ex ==
** (CompileError) lib/mix/tasks/release.ex:184: function reraise/2 undefined
(stdlib) lists.erl:1336: :lists.foreach/2
(stdlib) erl_eval.erl:657: :erl_eval.do_apply/6
(elixir) src/elixir.erl:157: :elixir.erl_eval/2
(elixir) src/elixir.erl:150: :elixir.eval_forms/4
(elixir) src/elixir_lexical.erl:17: :elixir_lexical.run/2
(elixir) src/elixir.erl:157: :elixir.erl_eval/2
could not compile dependency exrm, mix compile failed. You can recompile this dependency with `mix deps.compile exrm` or update it with `mix deps.update exrm`
The comments still talk about the old run api. needs to be updated for before_release / after_release.
Have a few questions. Just checked out this module last night for the first time and it's really wonderful, so thanks.
I was playing around with figuring out how to throw Upstart around this to start my erlang app on boot and to respawn it, but couldn't quite figure it out the way it forks the processes, it always seemed to hang. Anybody do anything like this before?
What is the preferred way to log, because in the past I would just redirect the output to a logfile but now I don't see a way to do that.
Cheers and Thank You,
Rob
I'm trying to use rpc per the readme. I get following:
[root@ucx50-4 mdse]# bin/mdse ping
pong
[root@ucx50-4 mdse]# bin/mdse rpc erlang now
Other: ["rpcterms"]
Usage: nodetool {ping|stop|restart|reboot}
What is the correct syntax to run the following in my project?
Mdse.AlarmManager.get_status
Is remote_console supposed to work on a system without elixir installed? I reviewed the generated bin/test script and it looks like iex is being called directly without any path. Nor could I find an iex executable in the release directory.
I can reproduce this problem on elixir 0.13.1 / exrm 0.5.0, but cannot get 0.13.2 / exrm 0.6.3 working (per previous issue) to try and reproduce.
Once Elixir v0.14.0 is out, the build pack could automatically compile and consolidate protocols. Calling mix compile.protocols
will generate a consolidated path. This path need to be added to the release package and once the release boots, all the beam files in the directory need to be explicitly loaded (while previous versions of the protocols must be deleted/purged).
Note exrm shouldn't, at any circumstance, get the consolidated protocols and override the protocols defined in the ebin directories of each application. Loading of the consolidated protocols must happen at boot time.
You can check a protocol has been consolidated by calling Protocol.consolidated?(Enumerable)
.
For more info, please check this commit: elixir-lang/elixir@e24cef0
/cc @ericmj
Hi Paul,
Following our discussion on IRC two days ago on deploying Dynamo apps I generated a lot of releases and noticed that, each time, it was creating a 'nil' folder with an empty file named '.compile.dynamo' in it.
Looks like some leftover which should have been cleaned up.
Not sure if this is due to exrm or related to something in Dynamo, if the latter feel free to close.
Centos install without erlang/elixir
Release build with elixir 0.13.3-dev / exrm 0.6.7
[root@localhost exrm_test]# ls
bin erts-6.0 lib releases
[root@localhost exrm_test]# bin/exrm_test2 start
/usr/bin/env: escript: No such file or directory
[root@localhost exrm_test]# ls
bin erts-6.0 lib log releases
[root@localhost exrm_test]# ll bin
total 2072
-rwxr-xr-x 1 admin games 2078734 May 20 2014 conform
-rwxr-xr-x 1 admin games 11978 May 20 2014 exrm_test2
-rw-r--r-- 1 admin games 4400 May 20 2014 install_upgrade.escript
-rw-r--r-- 1 admin games 4828 May 20 2014 nodetool
-r--r--r-- 1 admin 80 5283 Apr 30 21:52 start_clean.boot
[root@localhost exrm_test]#
From Elixir v0.13.1 and Erlang 17.0, Elixir will default to using the +fnu flag when starting the VM to force unicode encoding even on Linux systems. I would recommend adding this flag by default to releases too (or any other script that starts up the VM). Here is the relevant line on Elixir:
https://github.com/elixir-lang/elixir/blob/master/bin/elixir#L97
Thank you!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.