diff --git a/.gitignore b/.gitignore index 0a218c43ec..d41f12ba70 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,9 @@ .idea -.config/ -.local/ CMakeCache.txt CMakeFiles/ -Makefile -!scripts/Makefile cmake_install.cmake -scripts/xunittests.xml -scripts/powershell.inc -.bash_history +Makefile +!/scripts/Makefile +/.bash_history +/.local/ +/.config/ diff --git a/.gitmodules b/.gitmodules index 5b79583008..61529ee9ff 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,10 @@ [submodule "ext-src/pester"] path = ext-src/pester url = https://msostc.visualstudio.com/DefaultCollection/PS/_git/Pester +[submodule "src/monad-omi-provider"] + path = src/monad-omi-provider + url = https://msostc.visualstudio.com/DefaultCollection/PS/_git/monad-omi-provider +[submodule "src/omi"] + path = src/omi + url = https://msostc.visualstudio.com/DefaultCollection/PS/_git/omi + branch = OMI-Shell/OMI-PSRP-Support diff --git a/ext-src/pester b/ext-src/pester index dc5d388532..1232fc67a6 160000 --- a/ext-src/pester +++ b/ext-src/pester @@ -1 +1 @@ -Subproject commit dc5d388532499267e68c17c0a96153f7bc09c437 +Subproject commit 1232fc67a6a4b04a38cf6f9b14f3f9b77db34ccf diff --git a/scripts/.gitignore b/scripts/.gitignore index 6b1b27ea78..8110e6a848 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -1,24 +1,9 @@ -System.Collections.Immutable.*/ -System.Reflection.Metadata.*/ -Microsoft.Net.ToolsetCompilers.*/ -dotnetlibs/ -gen-all-files.txt -monad-src.diff -output.txt -string-resources-files.txt -string-resources-orig.txt -xunit.abstractions.*/ -xunit.core.*/ -xunit.extensibility.core.*/ -xunit.runner.console.*/ -TypeCatalogGen.exe -System.Collections.Immutable.dll -System.Reflection.Metadata.dll -commands-management-win.mk -commands-utility-win.mk -management-infrastructure-win.mk -system-automation-win.mk +*.txt +*.exe +*-tests.xml +*-win.mk CorePsTypeCatalog.cs +powershell.inc buildtemp/ exec_env/ - +libps/ diff --git a/scripts/HelloWorld.cs b/scripts/HelloWorld.cs new file mode 100644 index 0000000000..49fe647088 --- /dev/null +++ b/scripts/HelloWorld.cs @@ -0,0 +1,9 @@ +using System; + +internal class Program +{ + private static void Main() + { + Console.WriteLine("Hello World!"); + } +} diff --git a/scripts/Makefile b/scripts/Makefile index b335eb677b..499aead303 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -1,10 +1,8 @@ -.PHONY: all - -# this should go away and be automatically generated -include assembly-load-context.mk +# the monad-linux superproject +MONAD=$(realpath $(CURDIR)/..) # main references to the CoreCLR reference assemblies -MONAD_EXT=../src/monad-ext +MONAD_EXT=$(MONAD)/src/monad-ext TARGETING_PACK=$(MONAD_EXT)/coreclr/TargetingPack COREREF=$(addprefix -r:, $(shell ls $(TARGETING_PACK)/*.dll)) CORECLR_ASSEMBLY_BASE=$(MONAD_EXT)/coreclr/Runtime @@ -13,7 +11,7 @@ CORECLR_ASSEMBLY_BASE=$(MONAD_EXT)/coreclr/Runtime include powershell-run.mk # this variable is needed by module specific include makefiles below -ADMIN_GIT_ROOT=../src/monad +ADMIN_GIT_ROOT=$(MONAD)/src/monad # these are automatically generated from the PowerShell build sytem # - System.Management.Automation.dll (the main PS dll) @@ -25,12 +23,15 @@ include commands-utility.mk include management-infrastructure.mk include security.mk +# this should go away and be automatically generated +include assembly-load-context.mk + +# reference sets for the PowerShell assemblies MI_NATIVE_REF=-r:dotnetlibs/Microsoft.Management.Infrastructure.Native.dll MI_REF_ASSEMBLY=-r:$(MONAD_EXT)/PS/PS_refs_modil/microsoft.management.infrastructure.metadata_dll MI_ASSEMBLY=dotnetlibs/Microsoft.Management.Infrastructure.dll MI_REF=-r:$(MI_ASSEMBLY) -PRODUCT_BASE_REFS=$(COREREF) PRODUCT_MI_REFS=$(COREREF) $(MI_NATIVE_REF) PRODUCT_PS_REFS=$(COREREF) $(MI_REF) -r:dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET) PRODUCT_COMMANDS_REFS=$(COREREF) -r:dotnetlibs/System.Management.Automation.dll @@ -47,42 +48,43 @@ CSCOPTS_LIB_PS=$(CSCOPTS_LIB) -unsafe -define:CORECLR -define:_CORECLR /nowarn:C RUN_TARGETS=$(POWERSHELL_RUN_TARGETS) $(addprefix dotnetlibs/, Microsoft.PowerShell.Commands.Management.dll Microsoft.PowerShell.Commands.Utility.dll Microsoft.PowerShell.Security.dll api-ms-win-core-registry-l1-1-0.dll host_cmdline) +.PHONY: all all: dotnetlibs/System.Management.Automation.dll $(RUN_TARGETS) dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET) # this is the build rule for SMA.dll -dotnetlibs/System.Management.Automation.dll: prepare $(SYS_AUTO_SRCS) dotnetlibs/Microsoft.Management.Infrastructure.dll ../src/assembly-info/System.Management.Automation.assembly-info.cs dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET) $(SYS_AUTO_RES_SRCS) $(SYS_AUTO_RES_CS_SRCS) - $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(PRODUCT_PS_REFS) $(SYS_AUTO_SRCS) $(SYS_AUTO_RES_REF) $(SYS_AUTO_RES_CS_SRCS) ../src/assembly-info/System.Management.Automation.assembly-info.cs +dotnetlibs/System.Management.Automation.dll: $(MONAD)/src/assembly-info/System.Management.Automation.assembly-info.cs dotnetlibs/Microsoft.Management.Infrastructure.dll dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET) $(SYS_AUTO_SRCS) $(SYS_AUTO_RES_SRCS) $(SYS_AUTO_RES_CS_SRCS) buildtemp + $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(PRODUCT_PS_REFS) $(SYS_AUTO_SRCS) $(SYS_AUTO_RES_REF) $(SYS_AUTO_RES_CS_SRCS) $< # this is the build rule for MMI.dll -dotnetlibs/Microsoft.Management.Infrastructure.dll: prepare $(MAN_INFRA_SRCS) dotnetlibs/Microsoft.Management.Infrastructure.Native.dll ../src/assembly-info/Microsoft.Management.Infrastructure.assembly-info.cs $(MAN_INFRA_RES_SRCS) $(MAN_INFRA_RES_CS_SRCS) - $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(PRODUCT_MI_REFS) $(MAN_INFRA_SRCS) $(MAN_INFRA_RES_REF) $(MAN_INFRA_RES_CS_SRCS) ../src/assembly-info/Microsoft.Management.Infrastructure.assembly-info.cs +dotnetlibs/Microsoft.Management.Infrastructure.dll: $(MONAD)/src/assembly-info/Microsoft.Management.Infrastructure.assembly-info.cs dotnetlibs/Microsoft.Management.Infrastructure.Native.dll $(MAN_INFRA_SRCS) $(MAN_INFRA_RES_SRCS) $(MAN_INFRA_RES_CS_SRCS) buildtemp + $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(PRODUCT_MI_REFS) $(MAN_INFRA_SRCS) $(MAN_INFRA_RES_CS_SRCS) $(MAN_INFRA_RES_REF) $< # Commands -dotnetlibs/Microsoft.PowerShell.Commands.Management.dll: prepare $(COMMANDS_MANAGEMENT_SRCS) dotnetlibs/System.Management.Automation.dll dotnetlibs/Microsoft.PowerShell.Security.dll $(COMMANDS_MANAGEMENT_RES_SRCS) $(COMMANDS_MANAGEMENT_RES_CS_SRCS) $(MI_ASSEMBLY) - $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(PRODUCT_COMMANDS_REFS) $(COMMANDS_MANAGEMENT_SRCS) $(COMMANDS_MANAGEMENT_RES_CS_SRCS) $(COMMANDS_MANAGEMENT_RES_REF) $(MI_REF) -r:dotnetlibs/Microsoft.PowerShell.Security.dll +dotnetlibs/Microsoft.PowerShell.Commands.Management.dll: dotnetlibs/System.Management.Automation.dll dotnetlibs/Microsoft.PowerShell.Security.dll $(MI_ASSEMBLY) $(COMMANDS_MANAGEMENT_SRCS) $(COMMANDS_MANAGEMENT_RES_SRCS) $(COMMANDS_MANAGEMENT_RES_CS_SRCS) buildtemp + $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(PRODUCT_COMMANDS_REFS) $(MI_REF) $(COMMANDS_MANAGEMENT_SRCS) $(COMMANDS_MANAGEMENT_RES_CS_SRCS) $(COMMANDS_MANAGEMENT_RES_REF) -r:dotnetlibs/Microsoft.PowerShell.Security.dll -dotnetlibs/Microsoft.PowerShell.Commands.Utility.dll: prepare $(COMMANDS_UTILITY_SRCS) dotnetlibs/System.Management.Automation.dll $(COMMANDS_UTILITY_RES_SRCS) $(COMMANDS_UTILITY_RES_CS_SRCS) +dotnetlibs/Microsoft.PowerShell.Commands.Utility.dll: dotnetlibs/System.Management.Automation.dll $(COMMANDS_UTILITY_SRCS) $(COMMANDS_UTILITY_RES_SRCS) $(COMMANDS_UTILITY_RES_CS_SRCS) buildtemp $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(PRODUCT_COMMANDS_REFS) $(COMMANDS_UTILITY_SRCS) $(COMMANDS_UTILITY_RES_CS_SRCS) $(COMMANDS_UTILITY_RES_REF) -dotnetlibs/Microsoft.PowerShell.Security.dll: prepare $(SECURITY_SRCS) $(SECURITY_RES_SRCS) $(SECURITY_RES_CS_SRCS) +dotnetlibs/Microsoft.PowerShell.Security.dll: dotnetlibs/System.Management.Automation.dll $(SECURITY_SRCS) $(SECURITY_RES_SRCS) $(SECURITY_RES_CS_SRCS) buildtemp $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(PRODUCT_COMMANDS_REFS) $(SECURITY_SRCS) $(SECURITY_RES_CS_SRCS) $(SECURITY_RES_REF) # assembly load context -dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET): prepare $(ASSEMBLY_LOAD_CONTEXT_SRCS) - $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(PRODUCT_BASE_REFS) $(ASSEMBLY_LOAD_CONTEXT_SRCS) +dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET): $(ASSEMBLY_LOAD_CONTEXT_SRCS) buildtemp + $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(COREREF) $(ASSEMBLY_LOAD_CONTEXT_SRCS) # this one is built from stubs -MI_STUBS=../src/stubs/Microsoft.Management.Infrastructure.Native-stub.cs ../src/stubs/Microsoft.Management.Infrastructure.Native-stub-assembly-info.cs -dotnetlibs/Microsoft.Management.Infrastructure.Native.dll: prepare $(MI_STUBS) - $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(PRODUCT_BASE_REFS) $(MI_STUBS) +MI_STUBS=$(MONAD)/src/stubs/Microsoft.Management.Infrastructure.Native-stub.cs $(MONAD)/src/stubs/Microsoft.Management.Infrastructure.Native-stub-assembly-info.cs +dotnetlibs/Microsoft.Management.Infrastructure.Native.dll: $(MI_STUBS) buildtemp + $(CSC) -out:$@ $(CSCOPTS_LIB_PS) $(COREREF) $(MI_STUBS) # this creates the type catalog generator MPATH=/usr/lib/mono/4.5/Facades REFLECTION_METADATA=buildtemp/System.Reflection.Metadata.1.0.22/lib/dotnet/System.Reflection.Metadata.dll COLLECTIONS_IMMUTABLE=buildtemp/System.Collections.Immutable.1.1.37/lib/dotnet/System.Collections.Immutable.dll -buildtemp/TypeCatalogGen.exe: ../src/monad/monad/nttargets/assemblies/core/PSAssemblyLoadContext/TypeCatalogGen/TypeCatalogGen.cs $(REFLECTION_METADATA) $(COLLECTIONS_IMMUTABLE) +buildtemp/TypeCatalogGen.exe: $(ADMIN_GIT_ROOT)/monad/nttargets/assemblies/core/PSAssemblyLoadContext/TypeCatalogGen/TypeCatalogGen.cs $(REFLECTION_METADATA) $(COLLECTIONS_IMMUTABLE) buildtemp $(MCS) -out:$@ -target:exe -pkg:dotnet $(addprefix -r:, $(REFLECTION_METADATA) $(COLLECTIONS_IMMUTABLE) $(MPATH)/System.Runtime.dll $(MPATH)/System.Reflection.Primitives.dll $(MPATH)/System.IO.dll) $< # this generates the necessary file of CoreCLR references that is an artifact of the Windows build process @@ -97,137 +99,149 @@ powershell.inc: @echo '$(PROFILE_REFERENCES)' >> $@ # generate the Core PS type catalog -# this comes from: ../src/monad/monad/nttargets/assemblies/core/PSAssemblyLoadContext/makefile.inc +# this comes from: $(MONAD)/src/monad/monad/nttargets/assemblies/core/PSAssemblyLoadContext/makefile.inc CorePsTypeCatalog.cs: powershell.inc buildtemp/TypeCatalogGen.exe MONO_PATH=$(dir $(REFLECTION_METADATA)):$(dir $(COLLECTIONS_IMMUTABLE)) mono buildtemp/TypeCatalogGen.exe $< $@ $(MONAD_EXT)/coreclr/TargetingPack -# the pinvoke library libps.so - -LIBPS_BUILD=buildtemp/libps-build -$(LIBPS_BUILD)/Makefile: ../src/monad-native/src/CMakeLists.txt - mkdir -p $(LIBPS_BUILD) +# the native library, libps.so +MONAD_NATIVE=$(MONAD)/src/monad-native/src +LIBPS_BUILD=libps +$(LIBPS_BUILD)/Makefile: $(MONAD_NATIVE)/CMakeLists.txt # cached files can change the path to be incorrect, this must be cleaned - rm -f ../src/monad-native/src/CMakeCache.txt - rm -f ../src/monad-native/src/cmake_install.cmake - cd $(LIBPS_BUILD) && cmake ../../../src/monad-native/src/ + rm -f $(MONAD_NATIVE)/CMakeCache.txt + rm -f $(MONAD_NATIVE)/cmake_install.cmake + mkdir -p $(LIBPS_BUILD) + cd $(LIBPS_BUILD) && cmake $(MONAD_NATIVE) NATIVE_BINARIES=libps.so monad_native host_cmdline $(addprefix dotnetlibs/, $(NATIVE_BINARIES)): $(LIBPS_BUILD)/Makefile $(MAKE) -j -C $(LIBPS_BUILD) - mkdir -p dotnetlibs cp $(addprefix $(LIBPS_BUILD)/, $(notdir $@)) dotnetlibs -libps.so-test: $(addprefix dotnetlibs/, libps.so monad_native) - cd dotnetlibs && LD_LIBRARY_PATH=. ./monad_native +# C++ tests for monad-native - results in native-tests.xml +# see https://github.com/google/googletest +native-tests: dotnetlibs/monad_native + cd dotnetlibs && ./monad_native --gtest_output="xml:$(MONAD)/scripts/native-tests.xml" # this is a windows dll that is needed because CoreCLR tries to access # registry functions that don't exist on Linux and there is no other good # way of fixing this right now # (TODO linux: this should be removed by addressing it in CoreCLR) -dotnetlibs/api-ms-win-core-registry-l1-1-0.dll: ../src/win-dll/lib-api-ms-win-core-registry-l1-1-0.c - gcc -o $@ -fPIC -shared -Wall $^ +dotnetlibs/api-ms-win-core-registry-l1-1-0.dll: $(MONAD)/src/win-dll/lib-api-ms-win-core-registry-l1-1-0.c dotnetlibs + gcc -o $@ -fPIC -shared -Wall $< nuget.exe: wget 'https://dist.nuget.org/win-x86-commandline/latest/nuget.exe' -buildtemp: - mkdir -p buildtemp - -prepare: nuget.exe buildtemp +# this creates the build output directories and restores packages from NuGet +buildtemp: nuget.exe + mkdir -p $@ mono nuget.exe restore -PackagesDirectory buildtemp -# this is the execution environment from which all managed code is run -APP_BASE=exec_env/app_base - -# this is an internal target, it's not intended to be called manually -# -# it will: +# this is a phony target that will: # - create necessary directories for deployment layout # - copy all the PowerShell stuff into PowerShell's app_base # - copy the custom host and other scripts into PowerShell's app_base # - copy PS modules -# -# This rule does not copy coreclr, because the selection of debug or -# release CoreCLR depends on the actual run target. -internal-prepare-exec_env: runps.sh $(POWERSHELL_RUN_TARGETS) - rm -rf exec_env +# - copy xUnit libraries + +# this is the execution environment from which all managed code is run +APP_BASE=exec_env/app_base + +.PHONY: $(APP_BASE) +$(APP_BASE): runps.sh $(POWERSHELL_RUN_TARGETS) + rm -rf $@ mkdir -p $(APP_BASE)/Modules - mkdir -p exec_env/coreclr - cp ../src/monad/monad/miscfiles/display/*.ps1xml $(APP_BASE) - cp ../src/monad/monad/miscfiles/types/CoreClr/*.ps1xml $(APP_BASE) - cp -r ../src/monad/monad/miscfiles/modules/* $(APP_BASE)/Modules + cp $(ADMIN_GIT_ROOT)/monad/miscfiles/display/*.ps1xml $(APP_BASE) + cp $(ADMIN_GIT_ROOT)/monad/miscfiles/types/CoreClr/*.ps1xml $(APP_BASE) + cp -r $(ADMIN_GIT_ROOT)/monad/miscfiles/modules/* $(APP_BASE)/Modules cp -r dotnetlibs/*.dll $(APP_BASE) cp -r dotnetlibs/*.exe $(APP_BASE) cp -r dotnetlibs/*.so $(APP_BASE) cp dotnetlibs/host_cmdline $(APP_BASE) - cp -r ../ext-src/pester $(APP_BASE)/Modules/Pester + cp -r $(MONAD)/ext-src/pester $(APP_BASE)/Modules/Pester + cp -r $(MONAD_EXT)/xunit/xunit* $(APP_BASE) cp runps*.sh $(APP_BASE) -internal-prepare-clr: - cp -r $(CORECLR_ASSEMBLY_BASE)/* exec_env/coreclr/ +CORECLR=exec_env/coreclr +$(CORECLR): + rm -rf $@ + mkdir -p $@ + cp -r $(CORECLR_ASSEMBLY_BASE)/* $@ -run: $(RUN_TARGETS) internal-prepare-exec_env internal-prepare-clr +prepare: $(APP_BASE) $(CORECLR) + +run: $(RUN_TARGETS) prepare # execute a cmdlet, this will auto-load the utility module and print a, b and c in 3 lines $(APP_BASE)/runps-simple.sh '"a","b","c","a","a" | Select-Object -Unique' -run-interactive: $(RUN_TARGETS) internal-prepare-exec_env internal-prepare-clr +shell: $(RUN_TARGETS) prepare $(APP_BASE)/runps.sh -run-file: $(RUN_TARGETS) internal-prepare-exec_env internal-prepare-clr +run-interactive: shell + +run-file: $(RUN_TARGETS) prepare $(APP_BASE)/runps.sh --file $(PSSCRIPT) # easy way to run individual PowerShell scripts, `make script.ps1` where the path is relative to monad-linux/scripts (with TEMP set for Pester) -%.ps1: $(RUN_TARGETS) internal-prepare-exec_env internal-prepare-clr - TEMP=/tmp $(APP_BASE)/runps.sh --file ../../$@ +%.ps1: $(RUN_TARGETS) prepare + TEMP=/tmp $(APP_BASE)/runps.sh --file $(MONAD)/scripts/$@ -run-debugclr: $(RUN_TARGETS) internal-prepare-exec_env internal-prepare-clr - PAL_DBG_CHANNELS="+LOADER.TRACE" $(APP_BASE)/runps-simple.sh get-location +# compiles "Hello World" like executables using .NET Core +%.exe: %.cs $(CORECLR) buildtemp + $(CSC) -out:$@ $(CSCOPTS_BASE) -target:exe $(COREREF) $< + @echo run with monad-tty ./$(CORECLR)/corerun ./$@ -native-tests: dotnetlibs/monad_native - # execute the native C++ tests - cd dotnetlibs && ./monad_native - -# xUnit tests -TEST_FOLDER=../src/ps_test +# xUnit tests for PowerShell - results in xunit-tests.xml +# see https://xunit.github.io/ +TEST_FOLDER=$(MONAD)/src/ps_test TEST_SRCS=$(addprefix $(TEST_FOLDER)/, test_*.cs) +TEST_TARGETS=System.Management.Automation.dll Microsoft.PowerShell.Commands.Management.dll $(ASSEMBLY_LOAD_CONTEXT_TARGET) -$(APP_BASE)/xunit%: $(MONAD_EXT)/xunit/xunit% - cp -f $^ $@ +dotnetlibs/ps_test.dll: $(TEST_SRCS) $(addprefix dotnetlibs/, $(TEST_TARGETS)) buildtemp + $(CSC) $(CSCOPTS_LIB) -out:$@ $(addprefix -r:$(MONAD_EXT)/xunit/, xunit.core.dll xunit.assert.dll) $(addprefix -r:dotnetlibs/, $(TEST_TARGETS)) $(COREREF) $(TEST_SRCS) -$(APP_BASE)/ps_test.dll: prepare $(TEST_SRCS) $(addprefix $(APP_BASE)/, xunit.core.dll xunit.assert.dll) $(addprefix dotnetlibs/, System.Management.Automation.dll Microsoft.PowerShell.Commands.Management.dll $(ASSEMBLY_LOAD_CONTEXT_TARGET)) - $(CSC) $(CSCOPTS_LIB) -out:$@ $(addprefix -r:$(APP_BASE)/, xunit.core.dll xunit.assert.dll) $(addprefix -r:dotnetlibs/, System.Management.Automation.dll $(ASSEMBLY_LOAD_CONTEXT_TARGET)) $(COREREF) $(TEST_SRCS) +xunit-tests: dotnetlibs/ps_test.dll $(RUN_TARGETS) prepare + $(APP_BASE)/runps-test.sh ps_test.dll -xml $(MONAD)/scripts/xunit-tests.xml -xunit-tests: $(RUN_TARGETS) internal-prepare-exec_env internal-prepare-clr $(addprefix $(APP_BASE)/, ps_test.dll xunit.console.netcore.exe xunit.runner.utility.dll xunit.abstractions.dll xunit.execution.dll) - # execute the xUnit runner, with XML output - $(APP_BASE)/runps-test.sh ps_test.dll -xml ../../xunittests.xml +# Pester tests for PowerShell - results in pester-tests.xml +# see https://github.com/pester/Pester +# requires $TEMP to be set +pester-tests: $(RUN_TARGETS) prepare + $(APP_BASE)/runps-simple.sh 'cd $(MONAD)/src/pester-tests; $$env:TEMP="/tmp"; invoke-pester -OutputFile $(MONAD)/scripts/pester-tests.xml -OutputFormat NUnitXml' -pester-tests: $(RUN_TARGETS) internal-prepare-exec_env internal-prepare-clr - # execute the Pester tests, which needs a TEMP environment variable to be set - $(APP_BASE)/runps-simple.sh 'cd ../../../src/pester-tests; $$env:TEMP="/tmp"; invoke-pester' - -hashbang-tests: all - # execute the 3rdparty/hashbang example - PATH=$(PATH):$(shell pwd)/$(APP_BASE) $(shell pwd)/3rdparty/hashbang/script.ps1 +# 3rdparty "hashbang" example using runps-file +hashbang-tests: all prepare + PATH=$(PATH):$(MONAD)/scripts/$(APP_BASE) $(MONAD)/scripts/3rdparty/hashbang/script.ps1 test: native-tests xunit-tests pester-tests hashbang-tests -trace: $(RUN_TARGETS) internal-prepare-exec_env internal-prepare-clr +# debug/trace targets + +trace: $(RUN_TARGETS) prepare $(APP_BASE)/runps-simple-trace.sh get-location -debug: $(RUN_TARGETS) internal-prepare-exec_env internal-prepare-clr - # quoting here is a bit special if strings are passed in, because lldb seems to forward arguments strangely +run-debugclr: $(RUN_TARGETS) prepare + PAL_DBG_CHANNELS="+LOADER.TRACE" $(APP_BASE)/runps-simple.sh get-location + +# quoting here is a bit special if strings are passed in, because lldb +# seems to forward arguments strangely +debug: $(RUN_TARGETS) prepare $(APP_BASE)/runps-simple-debug.sh get-location -# clean native library, libps +# Cleaning +.PHONY: clean-native clean cleanall + clean-native: - rm -rf buildtemp/libps-build + rm -rf $(LIBPS_BUILD) clean: - rm -rf dotnetlibs exec_env powershell.inc + rm -rf dotnetlibs/* exec_env powershell.inc *-tests.xml -# clean built stuff + prepare step cleanall: clean clean-native - rm -rf buildtemp xunittests.xml + rm -rf buildtemp + +# Shell-in-a-box Docker setup docker-build: docker build --no-cache=false -t image_ps . diff --git a/scripts/build-run.sh b/scripts/build-run.sh deleted file mode 100755 index 6cc6199b3e..0000000000 --- a/scripts/build-run.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -CUID=$(id -u) -CUSER=$(id -un) -CGID=$(id -g) -CGROUP=$(id -gn) -DIR=/opt/monad-linux -VOLUME=$(dirname $(pwd))/:$DIR - -# creates new user in container matching the local user so that -# artifacts will be owned by the local user; set IMPERSONATE to false -# to disable and run as root, defaults to true -if [[ ! $IMPERSONATE ]]; then IMPERSONATE=true; fi -impersonate() -{ - if ! $IMPERSONATE; then return; fi - echo \ - groupadd -g $CGID $CGROUP '&&' \ - useradd -u $CUID -g $CGID -d $DIR $CUSER '&&' \ - sudo --set-home -u $CUSER -g $CGROUP -} - -docker run --rm \ - --volume $VOLUME \ - --workdir $DIR/scripts \ - $DOCKERFLAGS \ - andschwa/magrathea:latest \ - bash -c "$(impersonate) $*" diff --git a/scripts/build-tty.sh b/scripts/build-tty.sh deleted file mode 100755 index 311b786527..0000000000 --- a/scripts/build-tty.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -# Runs with a pseudo tty so that interactive shells can be opened -export DOCKERFLAGS="--interactive --tty" -./build-run.sh "$*" diff --git a/scripts/build.sh b/scripts/build.sh index 16175a2647..ede2218072 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,5 +1,4 @@ #!/usr/bin/env bash -# Runs by non-interactively, just attaches output -export DOCKERFLAGS="--attach STDOUT --attach STDERR" -./build-run.sh "$*" +source monad-docker.sh +monad-run $* diff --git a/scripts/dotnetlibs/.gitignore b/scripts/dotnetlibs/.gitignore new file mode 100644 index 0000000000..72e8ffc0db --- /dev/null +++ b/scripts/dotnetlibs/.gitignore @@ -0,0 +1 @@ +* diff --git a/scripts/get-current-ref.sh b/scripts/get-current-ref.sh deleted file mode 100755 index 3921a21e45..0000000000 --- a/scripts/get-current-ref.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -branch=$(git for-each-ref --format=$'%(objectname) %(refname:short)' refs/heads | awk "/^$(git rev-parse HEAD)/ {print \$2}") -echo $branch - diff --git a/scripts/monad-docker.sh b/scripts/monad-docker.sh new file mode 100755 index 0000000000..e99b6505a3 --- /dev/null +++ b/scripts/monad-docker.sh @@ -0,0 +1,42 @@ +# docker run magrathea without tty +monad-run() +{ + monad-docker-run "--attach STDOUT --attach STDERR" $* +} + +# docker run magrathea with interactive tty +monad-tty() +{ + monad-docker-run "--interactive --tty" $* +} + +# runs ephemeral andschwa/magrathea docker container with local +# directory mounted to /opt and workdir set to /opt/scripts +monad-docker-run() +{ + local CONSOLE=$1 + shift 1 + docker run --rm \ + --volume $(dirname $(pwd))/:/opt \ + --workdir /opt/scripts \ + $CONSOLE \ + andschwa/magrathea:latest \ + bash -c "$(monad-impersonate) bash -c '$*'" +} + +# creates new user in container matching the local user so that +# artifacts will be owned by the local user; set IMPERSONATE to false +# to disable and run as root, defaults to true +if [[ ! $IMPERSONATE ]]; then IMPERSONATE=true; fi +monad-impersonate() +{ + if ! $IMPERSONATE; then return; fi + local CUID=$(id -u) + local CUSER=$(id -un) + local CGID=$(id -g) + local CGROUP=$(id -gn) + echo \ + groupadd -g $CGID $CGROUP '&&' \ + useradd -u $CUID -g $CGID -d /opt $CUSER '&&' \ + sudo --set-home -u $CUSER -g $CGROUP -- +} diff --git a/scripts/simplebuild.sh b/scripts/simplebuild.sh deleted file mode 100755 index e609bd8308..0000000000 --- a/scripts/simplebuild.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -if [ ! -d ext-src/cppunit ]; then - echo "Please call from root folder of project" - exit 1 -fi - -pushd ext-src/cppunit -./autogen.sh -CWD=$(pwd) -if [ -f Makefile ]; then - make distclean -fi -./configure LD=clang LDFLAGS="-stdlib=libc++" CXX=clang++ CC=clang CXXFLAGS="-stdlib=libc++" --prefix=$CWD/../../externals/cppunit -make -make install - -popd - - diff --git a/src/monad b/src/monad index 9330fdf4ce..ef930a363b 160000 --- a/src/monad +++ b/src/monad @@ -1 +1 @@ -Subproject commit 9330fdf4ce15b1bfd12be3cdd5ee8a8969f92f25 +Subproject commit ef930a363b21180c02ee6148974d39938effa035 diff --git a/src/monad-ext b/src/monad-ext index dec304a9a8..210f7442f5 160000 --- a/src/monad-ext +++ b/src/monad-ext @@ -1 +1 @@ -Subproject commit dec304a9a8704f28176474072e83f439017bac6d +Subproject commit 210f7442f5c5eeae098f5205fb6a05756f164656 diff --git a/src/monad-omi-provider b/src/monad-omi-provider new file mode 160000 index 0000000000..7c7307925b --- /dev/null +++ b/src/monad-omi-provider @@ -0,0 +1 @@ +Subproject commit 7c7307925b81420bb6d8520a51bc759b4d52ea0a diff --git a/src/omi b/src/omi new file mode 160000 index 0000000000..1f81decc6a --- /dev/null +++ b/src/omi @@ -0,0 +1 @@ +Subproject commit 1f81decc6a74f1de619659a4dd8359b66814189b diff --git a/src/pester-tests/Test-DotNetAPI.Tests.ps1 b/src/pester-tests/Test-DotNetAPI.Tests.ps1 new file mode 100644 index 0000000000..2f942d00be --- /dev/null +++ b/src/pester-tests/Test-DotNetAPI.Tests.ps1 @@ -0,0 +1,25 @@ +Describe "Test-DotNetAPI" { + $posh_E = 2.718281828459045 + $posh_pi = 3.14159265358979 + + It "Should be able to use static .NET classes and get a constant" { + [System.Math]::E | Should Match $posh_E.ToString() + [System.Math]::PI | Should Match $posh_pi.ToString() + } + + It "Should be able to invoke a method" { + [System.Environment]::GetEnvironmentVariable("PATH") | Should Be $env:PATH + } + + It "Should not require 'system' in front of static classes" { + [Environment]::CommandLine | Should Be ([System.Environment]::CommandLine) + + [Math]::E | Should Be ([System.Math]::E) + } + + It "Should be able to create a new instance of a .Net object" { + [System.Guid]$guidVal = [System.Guid]::NewGuid() + + $guidVal.GetType().Name | Should Be "Guid" + } +} diff --git a/src/pester-tests/Test-Get-ItemProperty.Tests.ps1 b/src/pester-tests/Test-Get-ItemProperty.Tests.ps1 new file mode 100644 index 0000000000..75360ffdf4 --- /dev/null +++ b/src/pester-tests/Test-Get-ItemProperty.Tests.ps1 @@ -0,0 +1,65 @@ +Describe "Test-Get-ItemProperty" { + $currentDirectory = Split-Path . -Leaf + $parentDirectory = Split-Path .. -Leaf + if (Test-Path /tmp) + { + $tempDirectory = "/tmp/testfolder" + $testProvider = "/" + } + else + { + $tempDirectory = "~/testfolder" + $testProvider = "C" + } + + New-Item $tempDirectory -ItemType Directory -Force + $testfile = $tempDirectory + "/" + "testfile1" + + New-Item $testfile -ItemType file -Force + + It "Should be able to be called on in the current directory" { + { Get-ItemProperty . } | Should Not Throw + + $(Get-ItemProperty .).Name | Should Be $currentDirectory + } + + It "Should be able to be called on a parent directory" { + { Get-ItemProperty .. } | Should Not Throw + + (Get-ItemProperty ..).Name | Should Be $parentDirectory + } + + It "Should be able to be called on a directory using the path switch" { + { Get-ItemProperty -Path $tempDirectory } | Should Not Throw + } + + It "Should be able to be called on a file using the path switch" { + { Get-ItemProperty -Path $testfile } | Should Not Throw + } + + It "Should be able to access a property using the Path and name switches" { + { Get-ItemProperty -Path $testfile -Name fullname } | Should Not Throw + + $output = Get-ItemProperty -Path $testfile -Name fullname + + $output.PSPath | Should Not BeNullOrEmpty + + $output.PSDrive | Should Be $testprovider + + $output.PSProvider.Name | Should Be "FileSystem" + } + + It "Should be able to use the gp alias without error" { + { gp . } | Should Not Throw + { gp .. } | Should Not Throw + } + + It "Should have the same results between alias and cmdlet" { + $alias = gp -Path $testfile -Name fullname + $cmdlet = Get-ItemProperty -Path $testfile -Name fullname + + $alias.PSPath | Should Be $cmdlet.PSPath + $alias.PSDrive | Should Be $cmdlet.PSDrive + $alias.PSProvider.Name | Should Be $cmdlet.PSProvider.Name + } +} diff --git a/src/pester-tests/Test-Get-PSProvider.Tests.ps1 b/src/pester-tests/Test-Get-PSProvider.Tests.ps1 new file mode 100644 index 0000000000..33944c31b2 --- /dev/null +++ b/src/pester-tests/Test-Get-PSProvider.Tests.ps1 @@ -0,0 +1,25 @@ +Describe "Test-Get-PSProvider" { + It "Should be able to call with no parameters without error" { + { Get-PSProvider } | Should Not Throw + } + + It "Should be able to call the filesystem provider" { + { Get-PSProvider FileSystem } | Should Not Throw + + $actual = Get-PSProvider FileSystem + + $actual.Name | Should Be "FileSystem" + + $actual.Capabilities | Should Be "Filter, ShouldProcess, Credentials" + } + + It "Should be able to call a provider with a wildcard expression" { + { Get-PSProvider File*m } | Should Not Throw + } + + It "Should be able to pipe the output" { + $actual = Get-PSProvider + + { $actual | Format-List } | Should Not Throw + } +} diff --git a/src/pester-tests/Test-Mocks.ps1 b/src/pester-tests/Test-Mocks.ps1 new file mode 100644 index 0000000000..4b6a3e8876 --- /dev/null +++ b/src/pester-tests/Test-Mocks.ps1 @@ -0,0 +1,18 @@ +Function GetFileMock () { + $objs = @( [pscustomobject]@{ Size=4533816; Mode="-a---l"; LastWriteTime="9/1/2015 11:15 PM"; Name="explorer.exe" }, + [pscustomobject]@{ Size=994816; Mode="-a---l"; LastWriteTime="9/1/2015 11:13 PM"; Name="HelpPane.exe" }, + [pscustomobject]@{ Size=316640; Mode="-a---l"; LastWriteTime="9/1/2015 11:17 PM"; Name="WMSysPr9.prx" }, + [pscustomobject]@{ Size=215040; Mode="-a---l"; LastWriteTime="9/1/2015 11:20 PM"; Name="notepad.exe" }, + [pscustomobject]@{ Size=207239; Mode="-a----"; LastWriteTime="10/7/2015 2:37 PM"; Name="setupact.log" }, + [pscustomobject]@{ Size=181064; Mode="-a----"; LastWriteTime="9/9/2015 11:54 PM"; Name="PSEXESVC.EXE" }) + return $objs +} + +filter addOneToSizeProperty() { + $_.Size += 1 + $_ +} + +filter pipelineConsume() { + $_ +} diff --git a/src/pester-tests/Test-Select-Object.Tests.ps1 b/src/pester-tests/Test-Select-Object.Tests.ps1 new file mode 100644 index 0000000000..e0192ac09f --- /dev/null +++ b/src/pester-tests/Test-Select-Object.Tests.ps1 @@ -0,0 +1,116 @@ +. ./Test-Mocks.ps1 + +Describe "Select-Object" { + BeforeEach { + $dirObject = GetFileMock + $TestLength = 3 + } + + It "Handle piped input without error" { + { $dirObject | Select-Object } | Should Not Throw + } + + It "Should treat input as a single object with the inputObject parameter" { + $result = $(Select-Object -inputObject $dirObject -last $TestLength).Length + $expected = $dirObject.Length + + $result | Should Be $expected + } + + It "Should be able to use the alias" { + { $dirObject | select } | Should Not Throw + } + + It "Should have same result when using alias" { + $result = $dirObject | select + $expected = $dirObject | Select-Object + + $result | Should Be $expected + } + + It "Should return correct object with First parameter" { + $result = $dirObject | Select-Object -First $TestLength + + $result.Length | Should Be $TestLength + + for ($i=0; $i -lt $TestLength; $i++) + { + $result[$i].Name | Should Be $dirObject[$i].Name + } + } + + It "Should return correct object with Last parameter" { + $result = $dirObject | Select-Object -Last $TestLength + + $result.Length | Should Be $TestLength + + for ($i=0; $i -lt $TestLength; $i++) + { + $result[$i].Name | Should Be $dirObject[$dirObject.Length - $TestLength + $i].Name + } + } + + It "Should work correctly with Unique parameter" { + $result = ("a","b","c","a","a","a" | Select-Object -Unique).Length + $expected = 3 + + $result | Should Be $expected + } + + It "Should return correct object with Skip parameter" { + $result = $dirObject | Select-Object -Skip $TestLength + + $result.Length | Should Be ($dirObject.Length - $TestLength) + + for ($i=0; $i -lt $TestLength; $i++) + { + $result[$i].Name | Should Be $dirObject[$TestLength + $i].Name + } + } + + It "Should return an object with selected columns" { + $result = $dirObject | Select-Object -Property Name, Size + + $result.Length | Should Be $dirObject.Length + $result[0].Name | Should Be $dirObject[0].Name + $result[0].Size | Should Be $dirObject[0].Size + $result[0].Mode | Should BeNullOrEmpty + } + + It "Should send output to pipe properly" { + {$dirObject | Select-Object -Unique | pipelineConsume} | Should Not Throw + } + + It "Should select array indices with Index parameter" { + $firstIndex = 2 + $secondIndex = 4 + $result = $dirObject | Select-Object -Index $firstIndex, $secondIndex + + $result[0].Name | Should Be $dirObject[$firstIndex].Name + $result[1].Name | Should Be $dirObject[$secondIndex].Name + } + + # Note that these two tests will modify original values of $dirObject + + It "Should not wait when used without -Wait option" { + $orig1 = $dirObject[0].Size + $orig2 = $dirObject[$TestLength].Size + $result = $dirObject | addOneToSizeProperty | Select-Object -First $TestLength + + $result[0].Size | Should Be ($orig1 + 1) + $dirObject[0].Size | Should Be ($orig1 + 1) + $dirObject[$TestLength].Size | Should Be $orig2 + } + + It "Should wait when used with -Wait option" { + $orig1 = $dirObject[0].Size + $orig2 = $dirObject[$TestLength].Size + $result = $dirObject | addOneToSizeProperty | Select-Object -First $TestLength -Wait + + $result[0].Size | Should Be ($orig1 + 1) + $dirObject[0].Size | Should Be ($orig1 + 1) + $dirObject[$TestLength].Size | Should Be ($orig2 + 1) + } +} + + diff --git a/src/ps_test/test_CorePsPlatform.cs b/src/ps_test/test_CorePsPlatform.cs index e11826091e..0c6cc33614 100644 --- a/src/ps_test/test_CorePsPlatform.cs +++ b/src/ps_test/test_CorePsPlatform.cs @@ -134,5 +134,113 @@ namespace PSTests FileSystemInfo fd = new FileInfo(path); Assert.False(Platform.NonWindowsIsHardLink(fd)); } + + + [Fact] + public static void TestCommandLineArgvReturnsAnElement() + { + string testCommand= "Today"; + + string[] retval = Platform.CommandLineToArgv(testCommand); + + Assert.Equal(1, retval.Length); + } + + [Fact] + public static void TestCommandLineArgvWWithSpaces() + { + string testCommand= "Today is a good day or is it"; + + string[] retval = Platform.CommandLineToArgv(testCommand); + + Assert.Equal("Today", retval[0]); + Assert.Equal("is", retval[1]); + Assert.Equal("a", retval[2]); + Assert.Equal("good", retval[3]); + Assert.Equal("day", retval[4]); + Assert.Equal("or", retval[5]); + Assert.Equal("is", retval[6]); + Assert.Equal("it", retval[7]); + } + + [Fact] + public static void TestCommandLineToArgvWTabsAreTreatedAsSpaces() + { + string testCommand = "Today \t is a good day"; + + string[] retval = Platform.CommandLineToArgv(testCommand); + + Assert.Equal("Today", retval[0]); + Assert.Equal("is", retval[1]); + Assert.Equal("a", retval[2]); + Assert.Equal("good", retval[3]); + Assert.Equal("day", retval[4]); + } + + [Fact] + public static void TestCommandLineToArgvWQuotesAreArgs() + { + string testCommand = "Today is \"a good\" day"; + + string[] retval = Platform.CommandLineToArgv(testCommand); + + Assert.Equal(4, retval.Length); + Assert.Equal("Today", retval[0]); + Assert.Equal("is", retval[1]); + Assert.Equal("\"a good\"", retval[2]); + Assert.Equal("day", retval[3]); + } + + [Fact] + public static void TestCommandLineToArgvWEvenNumberBackSlashes() + { + string test1 = "a\\b c d"; + string test2 = "a\\b\\c d"; + string test3 = "a \\b\\c\\d"; + string test4 = "a\\\\\\b"; + string[] retval; + + retval = Platform.CommandLineToArgv(test1); + + Assert.Equal(3, retval.Length); + Assert.Equal("a\\b", retval[0]); + Assert.Equal("c", retval[1]); + Assert.Equal("d", retval[2]); + + retval = Platform.CommandLineToArgv(test2); + + Assert.Equal(2, retval.Length); + Assert.Equal("a\\b\\c", retval[0]); + Assert.Equal("d", retval[1]); + + retval = Platform.CommandLineToArgv(test3); + + Assert.Equal(2, retval.Length); + Assert.Equal("a", retval[0]); + Assert.Equal("\\b\\c\\d", retval[1]); + + retval = Platform.CommandLineToArgv(test4); + + Assert.Equal(1, retval.Length); + Assert.Equal("a\\\\\\b", retval[0]); + } + + [Fact] + public static void TestCommandLineToArgvwOddNumberWithBackSlashes() + { + string test1 = "a\\\"b"; + string test2 = "a\\\\\\\"b"; + string[] retval; + + retval = Platform.CommandLineToArgv(test1); + + Assert.Equal(1, retval.Length); + Assert.Equal("a\\\"b", retval[0]); + + retval = Platform.CommandLineToArgv(test2); + + Assert.Equal(1, retval.Length); + Assert.Equal("a\\\\\\\"b", retval[0]); + } } }