Jenkins 및 기타 등등으로 자동 빌드를 하기 위해서 필수적으로 들어가는 Command Line

Unity에서도 Command Line을 지원해주고 있습니다.


근데 이걸 어느 컬럼에 써야 될지 난감하긴 하네요.... 주된 내용이 C#이니 그리고 활용은 Unity뿐만 아니라 Command Line에서 사용 가능하니 C# 컬럼에서 작성하겠습니다.


기본적으로 Unity에서 Command Line을 지원하는데 그에 대한 정보는 

https://docs.unity3d.com/kr/current/Manual/CommandLineArguments.html 에 참조하시면 됩니다.


Jenkins에서는 기본적으로 plugin을 제공해주고 있고, 이부분은 다음에 설명을 하도록 하고 대충 사용 방법을 설명하면 이렇게 사용합니다.

 - Mac 기준

{유니티설치경로}/Unity.app/Contents/MacOS/Unity -quit -batchMode - buildTarget Android -projectPath 프로젝트경로 -excuteMethod 클래스명.함수명


프로젝트 경로가 Users/Dosinamja/project 이고 사용하는 함수가 AutoBuilder.BuildAndroid라고 했을 경우에는 다음과 같습니다.


/Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchMode -buildTarget Android -projectPath Users/Dosinamja/project -excuteMethod AutoBuilder.BuildAndroid


대충 이런식으로 사용됩니다.


이렇게 하면 Command Line 으로 빌드를 수행할수 있긴 하지만 사용하다가 보면 명령인자를 넘겨줘서 처리하고 싶을 경우가 많이 생깁니다. 그렇다고 매번 소스를 수정한 뒤에 빌드를 수행하기에는 매우 번거롭고 생산적이지 못하지요.


그래서 실질적으로 arguments 를 넘겨줘서 원하는 작업을 수행하기 위해서 작업이 필요합니다.

기본적으로 명령인자를  parsing 하여 우리가 원하는 값들을 뽑아내서 사용한다고 생각하면 된됩니다.


기본적인 코드는 GitHub에 올라와 있습니다.( 물론 제가 만든것은 아닙니다. )

https://github.com/EpixCode/CommandLineCustomArguments/blob/master/Assets/Scripts/Com/EpixCode/Util/CommandLineReader.cs#L76


#region Using

using System;

using System.Collections.Generic;

using System.Linq;

using UnityEngine;

#endregion


public class CommandLineReader

{

    //Config

    private const string CUSTOM_ARGS_PREFIX = "-CustomArgs:";

    private const char CUSTOM_ARGS_SEPARATOR = ';';


    public static string[] GetCommandLineArgs()

    {

        return Environment.GetCommandLineArgs();

    }


    public static string GetCommandLine()

    {

        string[] args = GetCommandLineArgs();

        if (args.Length > 0)

        {

            return string.Join(" ", args);

        }

        else

        {

            Debug.LogError("CommandLineReader.cs - GetCommandLine() - Can't find any command line arguments!");

            return "";

        }

    }


    public static Dictionary<string,string> GetCustomArguments()

    {

        Dictionary<string, string> customArgsDict = new Dictionary<string, string>();

        string[] commandLineArgs = GetCommandLineArgs();

        string[] customArgs;

        string[] customArgBuffer;

        string customArgsStr = "";


        try

        {

            customArgsStr = commandLineArgs.Where(row => row.Contains(CUSTOM_ARGS_PREFIX)).Single();

        }

        catch (Exception e)

        {

            Debug.LogError("CommandLineReader.cs - GetCustomArguments() - Can't retrieve any custom arguments in the command line [" + commandLineArgs + "]. Exception: " + e);

            return customArgsDict;

        }


        customArgsStr = customArgsStr.Replace(CUSTOM_ARGS_PREFIX, "");

        customArgs = customArgsStr.Split(CUSTOM_ARGS_SEPARATOR);


        foreach (string customArg in customArgs)

        {

            customArgBuffer = customArg.Split('=');

            if (customArgBuffer.Length == 2)

            {

                customArgsDict.Add(customArgBuffer[0], customArgBuffer[1]);

            }

            else

            {

                Debug.LogWarning("CommandLineReader.cs - GetCustomArguments() - The custom argument [" + customArg + "] seem to be malformed.");

            }

        }


        return customArgsDict;

    }


    public static string GetCustomArgument(string argumentName)

    {

        Dictionary<string, string> customArgsDict = GetCustomArguments();


        if (customArgsDict.ContainsKey(argumentName))

        {

            return customArgsDict[argumentName];

        }

        else

        {

            Debug.LogError("CommandLineReader.cs - GetCustomArgument() - Can't retrieve any custom argument named [" + argumentName + "] in the command line [" + GetCommandLine() + "].");

            return "";

        }

    }

}



사용방법은 다음과 같습니다.



/Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchMode -buildTarget Android -projectPath Users/Dosinamja/project -excuteMethod AutoBuilder.BuildAndroid -CustomArgs:Language=en_US;Version=1.02


이런식으로 인자를 붙여서 CommandLine 을 사용하면 됩니다.


.cs파일에서는 


public class AutoBuilder

{

static void BuildAndroid

{

string language = string.Empty;

language = CommandLineReader.GetCustomArgument("Language");

if( String.IsNullOrEmpty(language) == false && language == "en_US" )

{

// 해당 코드 수행.

}


string version = string.Empty;

version = CommandLineReader.GetCustomArgument("Version");

if( String.IsNullOrEmpty(version) == false && version == "1.02" )

{

// 해당 코드 수행.

}

}

}


이런식으로 작업하면 됩니다.

또 다른 방법으로는 매번 CustomArgs: 를 설정하기 싫으시면 BuildAndroid()함수를 호출하기 전에 명령인자를 죄다 저장한뒤에 특정 문자열 키를 저장하고 그 해당 키값을 가져쓰는 방식으로 사용하면 됩니다.


static void BuildAndroid

{

InitCommandLineArgs();

}


static private void InitCommandLineArgs()

{

string[] commandArgs;

commandArgs = Environment.GetCommandLineArgs();


for( int i = 0; i < commandArgs.Length; ++i )

{

// 명령인자 매개변수 앞에 특정 문자열을 파싱해서

// 해당하는 매개변수 명을 키값으로 하는 Dictionary 설정.

// 나중에 Dictionary에서 특정 키값으로 하는 값을 가져옴.

}

}


이렇게 사용하면 가능합니다. CommandLine을 좀 더 유연하게 사용하여 원하시는 작업 하시길 바랍니다.

'프로그래밍 > C#' 카테고리의 다른 글

partial classes  (0) 2016.11.21
JsonFx 파일 가독성 높게 저장하기  (0) 2016.11.21

MSDN에 정의 되어 있는 내용 입니다.


It is possible to split the definition of a class or a struct, an interface or a method over two or more source files. Each source file contains a section of the type or method definition, and all parts are combined when the application is compiled.



둘 이상의 소스 파일에 대해 클래스 또는 구조체, 인터페이스 또는 메소드의 정의를 분할 할 수 있습니다. 각 소스 파일에는 형식 또는 메서드 정의의 섹션이 포함되어 있으며 응용 프로그램이 컴파일 될 때 모든 파트가 결합됩니다.


C# 2.0부터 적용되어 있는 것으로 알고 있습니다.

사용하는 이유는 여러가지가 있습니다만 제가 생각하는 이유로는
1. 프로젝트에 여러사람이 접근해서 작업을 할 경우에 소스 merge에 이점을 두거나 해당 부분을 나눠서 작업을 할 수 있는 이점이 있습니다.
 - 예를 들어서 몬스터의 AI 부분 작업을 여러사람이 나눠서 하게 된다면 AI의 해당 부분들( 플레이어 공격, 휴식, 죽음 등등 )을 각각의 파일로 나눠서 작업하게 되면 나중에 접근하기도 쉽고, 나눠서 작업하기도 편합니다. 이후에 예를 설명 드리겠습니다.

2. MSDN에서 설명되어 있기를... Visual Studio에서는 Windows Forms, 웹 서비스 래퍼 코드 등을 만들 때이 방법을 사용합니다. Visual Studio로 만든 파일을 수정하지 않고 이러한 클래스를 사용하는 코드를 만들 수 있습니다.
- 뭐 대충 자동으로 생성되는 코드랑 작업자가 사용하는 코드를 분류해서 사용하면 실수를 미연에 방지할 수 있다는 내용입니다만 전 이런거 사용을 하지 않기 때문에 1번의 이유가 더 확실하죠.

< 간단한 코드를 예를 들어보이겠습니다. >


EnemyAI.cs

public partial class EnemyAI {

    public string Init() {

        return "Enemy AI Init";

    }

}


EnemyAI_Attack.cs

public partial class EnemyAI {

    public string Attack() {

        return "Enemy Attack!!!!";

    }

}


EnemyAI_Death.cs

public partial class EnemyAI {

    public string Death() 

    {

        if( HP > 0 )

            return "No Die";


        return "Enemy Death";

    }

}


Program.cs

public class Program {

    public static void Main() {

        EnemyAI enemy_ai = new EnemyAI();

        Console.WriteLine(enemy_ai.Init());

        Console.WriteLine(enemy_ai.Attack());

        Console.WriteLine(enemy_ai.Death());

    }

}


이런식으로 파일을 나눠서 작업을 하면 좀 더 명확하게 작업을 분류할 수 있고 나중에 특정 작업에 대해서 접근 하기도 쉬워집니다. 다만 너무 많아지면 나중에 오히려 분류하기 힘들어지니 너무 많은 분류는 자제하시는게 좋을 것 같네요.

< 정리 >

partial class는 CLR 수준이 아닌 C# Compiler 수준에서 처리되므로 많은 partial class를 만들어도 실제 컴파일시에 하나의 클래스로 수집하여 인식하므로 단일 코드로 취합합니다.

소스코드 수준에서만 허용됩니다. binary 시엔 허용되지 않습니다.

무분별한 partial class 의 사용은 더욱 복잡해질 소지가 있습니다.

여러 파일에 partial 클래스로 선언시 그 클래스의 멤버들을 보는 것은 복잡하겠지만 클래스뷰를 이용하면 partial을 모아서 한 클래스처럼 보실 수 있습니다.



자세한 사항은 https://msdn.microsoft.com/en-us/library/wa80x488.aspx 참고 하시길 바랍니다.

'프로그래밍 > C#' 카테고리의 다른 글

Command Line Reader 클래스  (0) 2016.11.21
JsonFx 파일 가독성 높게 저장하기  (0) 2016.11.21

기본적으로 C#에서 사용하는 Json Library는 여러종류가 있지만( 일단 알고 있는 종류는 몇개 안됨...) JsonFx에서 제대로 설정을 하지 않고 파일을 저장하면 One Line(!!!)으로 저장되는 경우가 있다. MB 단위로 파일이 저장됐는데 One Line으로 나오면... ㅠㅠ

JsonFx 에서 개행단위로 저장되는 옵션이다.


using (StreamWriter writer = File.CreateText(txtFilePath))

{

            JsonFx.Json.JsonWriter cJsonWriter = new JsonFx.Json.JsonWriter(writer);

            cJsonWriter.Settings.PrettyPrint = true;

            cJsonWriter.Write(Info);   // 저장하는 Json 포맷

}

'프로그래밍 > C#' 카테고리의 다른 글

Command Line Reader 클래스  (0) 2016.11.21
partial classes  (0) 2016.11.21

+ Recent posts