Beispiel #1
0
        private static IEnumerable<IFile> Install(NuGetConfiguration configuration, DirectoryPath appDataPath)
        {
            var fileSystem = new FileSystem();
            var environment = new CakeEnvironment();
            var globber = new Globber(fileSystem, environment);

            var installer = new NuGetInstaller(fileSystem, globber);
            return installer.Install(configuration, appDataPath, true);
        }
        public FakeCakeContext ()
        {
            testsDir = new DirectoryPath (
                System.IO.Path.GetFullPath (AppDomain.CurrentDomain.BaseDirectory));
            
            var fileSystem = new FileSystem ();
            var environment = new CakeEnvironment ();
            var globber = new Globber (fileSystem, environment);
            log = new FakeLog ();
            var args = new FakeCakeArguments ();
            var processRunner = new ProcessRunner (environment, log);
            var registry = new WindowsRegistry ();

            context = new CakeContext (fileSystem, environment, globber, log, args, processRunner, registry);
            context.Environment.WorkingDirectory = testsDir;
        }
Beispiel #3
0
 public FakeCakeContext ()
 {
     testsDir = new DirectoryPath (
         System.IO.Path.GetFullPath (AppDomain.CurrentDomain.BaseDirectory));
     
     var fileSystem = new FileSystem ();
     var environment = new CakeEnvironment (new CakePlatform (), new CakeRuntime ());
     var globber = new Globber (fileSystem, environment);
     log = new FakeLog ();
     var args = new FakeCakeArguments ();
     var processRunner = new ProcessRunner (environment, log);
     var registry = new WindowsRegistry ();
     var toolRepo = new ToolRepository (environment);
     var config = new Core.Configuration.CakeConfigurationProvider (fileSystem, environment).CreateConfiguration (testsDir, new Dictionary<string, string> ());
     var toolResolutionStrategy = new ToolResolutionStrategy (fileSystem, environment, globber, config);
     var toolLocator = new ToolLocator (environment, toolRepo, toolResolutionStrategy);
     context = new CakeContext (fileSystem, environment, globber, log, args, processRunner, registry, toolLocator);
     context.Environment.WorkingDirectory = testsDir;
 }
Beispiel #4
0
        public FakeCakeContext ()
        {
            testsDir = new DirectoryPath (
                System.IO.Path.GetDirectoryName (System.Reflection.Assembly.GetExecutingAssembly ().Location));

            var fileSystem = new FileSystem ();
            var environment = new CakeEnvironment ();
            var globber = new Globber (fileSystem, environment);
            log = new FakeLog ();
            var args = new FakeCakeArguments ();
            var processRunner = new ProcessRunner (environment, log);
            var registry = new WindowsRegistry ();
            var toolRepo = new ToolRepository (environment);
            var config = new Core.Configuration.CakeConfigurationProvider (fileSystem, environment).CreateConfiguration (new Dictionary<string, string> ());
            var toolResStrat = new ToolResolutionStrategy (fileSystem, environment, globber, config);
            var toolLocator = new ToolLocator (environment, toolRepo, toolResStrat);

            context = new CakeContext (fileSystem, environment, globber, log, args, processRunner, registry, toolLocator);
            context.Environment.WorkingDirectory = testsDir;
        }
        /// <summary>
        /// Gets the dynamic parameters for the clear-itemproperty cmdlet.
        /// </summary>
        /// <param name="path">
        /// The path to the item if it was specified on the command line.
        /// </param>
        /// <param name="propertyToClear">
        /// A property table containing the property to clear.
        /// </param>
        /// <param name="context">
        /// The context which the core command is running.
        /// </param>
        /// <returns>
        /// An object that has properties and fields decorated with
        /// parsing attributes similar to a cmdlet class.
        /// </returns>
        /// <exception cref="ProviderNotFoundException">
        /// If the <paramref name="path"/> refers to a provider that could not be found.
        /// </exception>
        /// <exception cref="DriveNotFoundException">
        /// If the <paramref name="path"/> refers to a drive that could not be found.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// If the provider that the <paramref name="path"/> refers to does
        /// not support this operation.
        /// </exception>
        /// <exception cref="ProviderInvocationException">
        /// If the provider threw an exception.
        /// </exception>
        /// <exception cref="ItemNotFoundException">
        /// If <paramref name="path"/> does not contain glob characters and
        /// could not be found.
        /// </exception>
        internal object ClearPropertyDynamicParameters(
            string path,
            Collection <string> propertyToClear,
            CmdletProviderContext context)
        {
            if (path == null)
            {
                return(null);
            }

            ProviderInfo   provider         = null;
            CmdletProvider providerInstance = null;

            CmdletProviderContext newContext =
                new CmdletProviderContext(context);

            newContext.SetFilters(
                new Collection <string>(),
                new Collection <string>(),
                null);

            Collection <string> providerPaths =
                Globber.GetGlobbedProviderPathsFromMonadPath(
                    path,
                    true,
                    newContext,
                    out provider,
                    out providerInstance);

            if (providerPaths.Count > 0)
            {
                // Get the dynamic parameters for the first resolved path

                return(ClearPropertyDynamicParameters(providerInstance, providerPaths[0], propertyToClear, newContext));
            }

            return(null);
        }
        /// <summary>
        /// Gets the specified properties from the specified item.
        /// </summary>
        /// <param name="paths">
        /// The path(s) to the item(s) to get the properties from.
        /// </param>
        /// <param name="providerSpecificPickList">
        /// A list of the properties that the provider should return.
        /// </param>
        /// <param name="context">
        /// The context which the core command is running.
        /// </param>
        /// <returns>
        /// Nothing. A PSObject representing the properties should be written to the
        /// context.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="path"/> is null.
        /// </exception>
        /// <exception cref="ProviderNotFoundException">
        /// If the <paramref name="path"/> refers to a provider that could not be found.
        /// </exception>
        /// <exception cref="DriveNotFoundException">
        /// If the <paramref name="path"/> refers to a drive that could not be found.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// If the provider that the <paramref name="path"/> refers to does
        /// not support this operation.
        /// </exception>
        /// <exception cref="ProviderInvocationException">
        /// If the provider threw an exception.
        /// </exception>
        /// <exception cref="ItemNotFoundException">
        /// If <paramref name="path"/> does not contain glob characters and
        /// could not be found.
        /// </exception>
        internal void GetProperty(
            string[] paths,
            Collection <string> providerSpecificPickList,
            CmdletProviderContext context)
        {
            if (paths == null)
            {
                throw PSTraceSource.NewArgumentNullException(nameof(paths));
            }

            foreach (string path in paths)
            {
                if (path == null)
                {
                    throw PSTraceSource.NewArgumentNullException(nameof(paths));
                }

                ProviderInfo   provider         = null;
                CmdletProvider providerInstance = null;

                Collection <string> providerPaths =
                    Globber.GetGlobbedProviderPathsFromMonadPath(
                        path,
                        false,
                        context,
                        out provider,
                        out providerInstance);

                foreach (string providerPath in providerPaths)
                {
                    GetPropertyPrivate(
                        providerInstance,
                        providerPath,
                        providerSpecificPickList,
                        context);
                }
            }
        }
        /// <summary>
        /// Gets the security descriptor from the specified item.
        /// </summary>
        /// <param name="path">
        /// The path to the item to retrieve the security descriptor from.
        /// </param>
        /// <param name="sections">
        /// Specifies the parts of a security descriptor to retrieve.
        /// </param>
        /// <returns>
        /// Nothing. The security descriptor for the item at the specified path is
        /// written to the context.
        /// </returns>
        /// <exception cref="ItemNotFoundException">
        /// If <paramref name="path"/> does not contain glob characters and
        /// could not be found.
        /// </exception>
        internal ObjectSecurity NewSecurityDescriptorFromPath(
            string path,
            AccessControlSections sections)
        {
            ObjectSecurity sd = null;

            if (path == null)
            {
                throw PSTraceSource.NewArgumentNullException(nameof(path));
            }

            ProviderInfo provider = null;

            CmdletProvider      providerInstance = null;
            Collection <string> providerPaths    =
                Globber.GetGlobbedProviderPathsFromMonadPath(
                    path,
                    false,
                    out provider,
                    out providerInstance);

            //
            // path must resolve to exact 1 item,
            // any other case is an error
            //
            if (providerPaths.Count == 1)
            {
                sd = NewSecurityDescriptorFromPath(providerInstance,
                                                   providerPaths[0],
                                                   sections);
            }
            else
            {
                throw PSTraceSource.NewArgumentException(nameof(path));
            }

            return(sd);
        }
        public static DocumentModel Download(
            DirectoryPath appDataPath,
            NuGetConfiguration configuration,
            out string version)
        {
            var fileSystem  = new FileSystem();
            var environment = new CakeEnvironment();
            var globber     = new Globber(fileSystem, environment);
            var installer   = new NuGetInstaller(fileSystem, globber);

            var files = new Dictionary <string, IDocumentationMetadata>();

            foreach (var package in configuration.Packages)
            {
                var packageFiles = installer.Install(package, appDataPath);
                foreach (var packageFile in packageFiles)
                {
                    files.Add(packageFile.Path.FullPath, package.Metadata);
                }
            }

            // Find Cake.exe.
            version = "0.5.2"; // Default to this version if we could not find.
            var exe = files.Keys.FirstOrDefault(x => x.EndsWith("Cake.Core.dll"));

            if (exe != null)
            {
                var name = AssemblyName.GetAssemblyName(exe);
                if (name != null)
                {
                    version = $"{name.Version.Major}.{name.Version.Minor}.{name.Version.Build}";
                }
            }

            // Build the model.
            return(new DocumentModelBuilder()
                   .BuildModel(files));
        }
Beispiel #9
0
        public static DocumentModel Download(
            DirectoryPath appDataPath, 
            NuGetConfiguration configuration, 
            out string version)
        {
            var fileSystem = new FileSystem();
            var environment = new CakeEnvironment();
            var globber = new Globber(fileSystem, environment);
            var installer = new NuGetInstaller(fileSystem, globber);

            var files = new Dictionary<string, IDocumentationMetadata>();
            foreach (var package in configuration.Packages)
            {
                var packageFiles = installer.Install(package, appDataPath);
                foreach (var packageFile in packageFiles)
                {
                    files.Add(packageFile.Path.FullPath, package.Metadata);
                }
            }

            // Find Cake.exe.
            version = "0.5.2"; // Default to this version if we could not find.
            var exe = files.Keys.FirstOrDefault(x => x.EndsWith("Cake.Core.dll"));
            if (exe != null)
            {
                var name = AssemblyName.GetAssemblyName(exe);
                if (name != null)
                {
                    version = string.Format("{0}.{1}.{2}",
                        name.Version.Major, name.Version.Minor,
                        name.Version.Build);
                }
            }

            // Build the model.
            return new DocumentModelBuilder()
                .BuildModel(files);
        }
Beispiel #10
0
        internal void Rename(string path, string newName, ProviderRuntime runtime)
        {
            CmdletProvider provider;
            var            globbed = Globber.GetGlobbedProviderPaths(path, runtime, out provider);

            if (globbed.Count != 1)
            {
                throw new PSArgumentException("Cannot rename more than one item", "MultipleItemsRename", ErrorCategory.InvalidArgument);
            }
            path = globbed[0];
            var containerProvider = CmdletProvider.As <ContainerCmdletProvider>(provider);

            // TODO: I think Powershell checks whether we are currently in the path we want to remove
            //       (or a subpath). Check this and throw an error if it's true
            try
            {
                containerProvider.RenameItem(path, newName, runtime);
            }
            catch (Exception e)
            {
                HandleCmdletProviderInvocationException(e);
            }
        }
            public void WildcardShouldMatchZeroOrMore()
            {
                // Given
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/");
                fileProvider.AddDirectory("/root");
                fileProvider.AddDirectory("/root/a");
                fileProvider.AddDirectory("/root/a/b");
                fileProvider.AddDirectory("/root/d");
                fileProvider.AddFile("/root/a/x.txt");
                fileProvider.AddFile("/root/a/b/x.txt");
                fileProvider.AddFile("/root/a/b/.txt");
                fileProvider.AddFile("/root/d/x.txt");
                IDirectory directory = fileProvider.GetDirectory("/");

                // When
                IEnumerable <IFile> matches = Globber.GetFiles(directory, new[] { "root/**/*.txt" });

                // Then
                matches.Select(x => x.Path.FullPath).ShouldBe(
                    new[] { "/root/a/x.txt", "/root/a/b/x.txt", "/root/a/b/.txt", "/root/d/x.txt" }, true);
            }
Beispiel #12
0
            public void RecursiveWildcardTests(string directoryPath, string[] patterns, string[] resultPaths)
            {
                // Given
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/a");
                fileProvider.AddDirectory("/a/b");
                fileProvider.AddDirectory("/a/b/c");
                fileProvider.AddDirectory("/a/b/c/d");
                fileProvider.AddDirectory("/a/b/c/d/e");
                fileProvider.AddDirectory("/a/b/c/d/e/1");
                fileProvider.AddDirectory("/a/b/c/d/e/1/2");
                fileProvider.AddFile("/a/b/c/d/e/1/2/3.txt");
                IDirectory directory = fileProvider.GetDirectory(directoryPath);

                // When
                IEnumerable <IFile> matches = Globber.GetFiles(directory, patterns);
                IEnumerable <IFile> matchesReversedSlash = Globber.GetFiles(directory, patterns.Select(x => x.Replace("/", "\\")));

                // Then
                CollectionAssert.AreEquivalent(resultPaths, matches.Select(x => x.Path.FullPath));
                CollectionAssert.AreEquivalent(resultPaths, matchesReversedSlash.Select(x => x.Path.FullPath));
            }
Beispiel #13
0
        public FileCopyFixture()
        {
            // Setup the target directory.
            TargetDirectory = Substitute.For <IDirectory>();
            TargetDirectory.Exists.Returns(true);

            // Setup the files in the file system.
            SourceFilePaths = new List <FilePath>();
            TargetFiles     = new List <IFile>();
            TargetFilePaths = new List <FilePath>();
            CreateTargetFile("./file1.txt", "/Working/file1.txt");
            CreateTargetFile("./file2.txt", "/Working/file2.txt");

            // Setup the globber to return all files for wild card.
            Globber = Substitute.For <IGlobber>();
            Globber.Match("*").Returns(c => TargetFilePaths);

            // Setup the file system to return correct directories when asked for.
            FileSystem = Substitute.For <IFileSystem>();
            FileSystem.GetDirectory(Arg.Is <DirectoryPath>(p => p.FullPath == "/Working/target")).Returns(c => TargetDirectory);
            FileSystem.GetFile(Arg.Is <FilePath>(p => p.FullPath == TargetFilePaths[0].FullPath)).Returns(c => TargetFiles[0]);
            FileSystem.GetFile(Arg.Is <FilePath>(p => p.FullPath == TargetFilePaths[1].FullPath)).Returns(c => TargetFiles[1]);

            // Set the working directory.
            Environment = Substitute.For <ICakeEnvironment>();
            Environment.WorkingDirectory.Returns("/Working");

            // Setup the logger
            Log = new FakeLog();

            // Prepare the context.
            Context = Substitute.For <ICakeContext>();
            Context.FileSystem.Returns(FileSystem);
            Context.Environment.Returns(Environment);
            Context.Globber.Returns(Globber);
            Context.Log.Returns(Log);
        }
Beispiel #14
0
        /// <summary>
        /// Sets the specified object to the specified value.
        /// </summary>
        /// <param name="paths">
        /// The path(s) to the object. It can be either a relative (most common)
        /// or absolute path.
        /// </param>
        /// <param name="value">
        /// The new value of the item at the specified path.
        /// </param>
        /// <param name="context">
        /// The context which the core command is running.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="path"/> is null.
        /// </exception>
        /// <exception cref="ProviderNotFoundException">
        /// If the <paramref name="path"/> refers to a provider that could not be found.
        /// </exception>
        /// <exception cref="DriveNotFoundException">
        /// If the <paramref name="path"/> refers to a drive that could not be found.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// If the provider that the <paramref name="path"/> refers to does
        /// not support this operation.
        /// </exception>
        /// <exception cref="ProviderInvocationException">
        /// If the provider threw an exception.
        /// </exception>
        /// <exception cref="ItemNotFoundException">
        /// If <paramref name="path"/> does not contain glob characters and
        /// could not be found.
        /// </exception>
        internal void SetItem(
            string[] paths,
            object value,
            CmdletProviderContext context)
        {
            if (paths == null)
            {
                throw PSTraceSource.NewArgumentNullException("paths");
            }

            foreach (string path in paths)
            {
                if (path == null)
                {
                    throw PSTraceSource.NewArgumentNullException("paths");
                }

                ProviderInfo   provider         = null;
                CmdletProvider providerInstance = null;

                Collection <string> providerPaths =
                    Globber.GetGlobbedProviderPathsFromMonadPath(
                        path,
                        true,
                        context,
                        out provider,
                        out providerInstance);

                if (providerPaths != null)
                {
                    foreach (string providerPath in providerPaths)
                    {
                        SetItem(providerInstance, providerPath, value, context);
                    }
                }
            }
        }
 internal void Clear(string[] path, ProviderRuntime runtime)
 {
     foreach (var curPath in path)
     {
         CmdletProvider provider;
         var            globbedPaths    = Globber.GetGlobbedProviderPaths(curPath, runtime, false, out provider);
         var            contentProvider = CmdletProvider.As <IContentCmdletProvider>(provider);
         provider.ProviderRuntime = runtime; // make sure the runtime is set!
         foreach (var p in globbedPaths)
         {
             try
             {
                 if (Item.Exists(p, runtime))
                 {
                     contentProvider.ClearContent(p);
                 }
             }
             catch (Exception e)
             {
                 HandleCmdletProviderInvocationException(e);
             }
         }
     }
 }
        public FakeCakeContext()
        {
            testsDir = new DirectoryPath(
                System.IO.Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory));

            var fileSystem = new FileSystem();

            log = new FakeLog();
            var runtime     = new CakeRuntime();
            var platform    = new FakePlatform(PlatformFamily.Windows);
            var environment = new CakeEnvironment(platform, runtime, log);
            var globber     = new Globber(fileSystem, environment);

            var args          = new FakeCakeArguments();
            var processRunner = new ProcessRunner(environment, log);
            var registry      = new WindowsRegistry();

            var          toolRepository         = new ToolRepository(environment);
            var          toolResolutionStrategy = new ToolResolutionStrategy(fileSystem, environment, globber, new FakeConfiguration());
            IToolLocator tools = new ToolLocator(environment, toolRepository, toolResolutionStrategy);

            context = new CakeContext(fileSystem, environment, globber, log, args, processRunner, registry, tools);
            context.Environment.WorkingDirectory = testsDir;
        }
Beispiel #17
0
        /// <summary>
        /// Clears the specified item. Depending on the provider that the path
        /// maps to, this could mean the properties and/or content and/or value is
        /// cleared.
        /// </summary>
        /// <param name="paths">
        /// The path(s) to the object. It can be either a relative (most common)
        /// or absolute path.
        /// </param>
        /// <param name="context">
        /// The context which the core command is running.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="path"/> is null.
        /// </exception>
        /// <exception cref="ProviderNotFoundException">
        /// If the <paramref name="path"/> refers to a provider that could not be found.
        /// </exception>
        /// <exception cref="DriveNotFoundException">
        /// If the <paramref name="path"/> refers to a drive that could not be found.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// If the provider that the <paramref name="path"/> refers to does
        /// not support this operation.
        /// </exception>
        /// <exception cref="ProviderInvocationException">
        /// If the provider threw an exception.
        /// </exception>
        /// <exception cref="ItemNotFoundException">
        /// If <paramref name="path"/> does not contain glob characters and
        /// could not be found.
        /// </exception>
        internal void ClearItem(
            string[] paths,
            CmdletProviderContext context)
        {
            if (paths == null)
            {
                throw PSTraceSource.NewArgumentNullException("paths");
            }

            ProviderInfo   provider         = null;
            CmdletProvider providerInstance = null;

            foreach (string path in paths)
            {
                if (path == null)
                {
                    throw PSTraceSource.NewArgumentNullException("paths");
                }

                Collection <string> providerPaths =
                    Globber.GetGlobbedProviderPathsFromMonadPath(
                        path,
                        false,
                        context,
                        out provider,
                        out providerInstance);

                if (providerPaths != null)
                {
                    foreach (string providerPath in providerPaths)
                    {
                        ClearItemPrivate(providerInstance, providerPath, context);
                    }
                }
            }
        }
Beispiel #18
0
            public void Should_Zip_Provided_Directory()
            {
                // Given
                var environment = FakeEnvironment.CreateUnixEnvironment();
                var fileSystem = new FakeFileSystem(environment);
                var globber = new Globber(fileSystem, environment);
                var context = new CakeContextFixture {
                    Environment = environment, FileSystem = fileSystem, Globber = globber
                }.CreateContext();

                fileSystem.CreateDirectory("/Dir0"); // empty directory
                fileSystem.CreateFile("/File1.txt").SetContent("1");
                fileSystem.CreateFile("/Dir1/File2.txt").SetContent("22");
                fileSystem.CreateFile("/Dir2/File3.txt").SetContent("333");
                fileSystem.CreateFile("/Dir2/Dir3/File4.txt").SetContent("4444");
                fileSystem.CreateFile("/Dir2/Dir3/File5.txt").SetContent("55555");
                var log    = Substitute.For <ICakeLog>();
                var zipper = new Zipper(fileSystem, environment, log);

                // When
                zipper.Zip("/", "/Root.zip", context.GetPaths("/**/*"));

                // Then
                var archive = new ZipArchive(fileSystem.GetFile("/Root.zip").Open(FileMode.Open, FileAccess.Read, FileShare.Read));

                Assert.True(archive.Entries.Count == 9);
                Assert.True(archive.GetEntry("Dir0/")?.Length == 0); // directory entries; includes empty directories
                Assert.True(archive.GetEntry("Dir1/")?.Length == 0);
                Assert.True(archive.GetEntry("Dir2/")?.Length == 0);
                Assert.True(archive.GetEntry("Dir2/Dir3/")?.Length == 0);
                Assert.True(archive.GetEntry("File1.txt")?.Length == 1); // file entries
                Assert.True(archive.GetEntry("Dir1/File2.txt")?.Length == 2);
                Assert.True(archive.GetEntry("Dir2/File3.txt")?.Length == 3);
                Assert.True(archive.GetEntry("Dir2/Dir3/File4.txt")?.Length == 4);
                Assert.True(archive.GetEntry("Dir2/Dir3/File5.txt")?.Length == 5);
            }
Beispiel #19
0
        /// <summary>
        /// Changes the current working directory to the path specified.
        /// </summary>
        /// <param name="path">
        /// The path of the new current working directory.
        /// </param>
        /// <param name="context">
        /// The context the provider uses when performing the operation.
        /// </param>
        /// <param name="literalPath">
        /// Indicate if the path is a literal path.
        /// </param>
        /// <returns>
        /// The PathInfo object representing the path of the location
        /// that was set.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="path"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// If <paramref name="path"/> does not exist, is not a container, or
        /// resolved to multiple containers.
        /// </exception>
        /// <exception cref="ProviderNotFoundException">
        /// If <paramref name="path"/> refers to a provider that does not exist.
        /// </exception>
        /// <exception cref="DriveNotFoundException">
        /// If <paramref name="path"/> refers to a drive that does not exist.
        /// </exception>
        /// <exception cref="ProviderInvocationException">
        /// If the provider associated with <paramref name="path"/> threw an
        /// exception.
        /// </exception>
        /// <exception cref="ItemNotFoundException">
        /// If the <paramref name="path"/> could not be resolved.
        /// </exception>
        internal PathInfo SetLocation(string path, CmdletProviderContext context, bool literalPath)
        {
            if (path == null)
            {
                throw PSTraceSource.NewArgumentNullException("path");
            }

            PathInfo     current      = CurrentLocation;
            string       originalPath = path;
            string       driveName    = null;
            ProviderInfo provider     = null;
            string       providerId   = null;

            switch (originalPath)
            {
            case string originalPathSwitch when !literalPath && originalPathSwitch.Equals("-", StringComparison.Ordinal):
                if (_setLocationHistory.UndoCount <= 0)
                {
                    throw new InvalidOperationException(SessionStateStrings.LocationUndoStackIsEmpty);
                }

                path = _setLocationHistory.Undo(this.CurrentLocation).Path;
                break;

            case string originalPathSwitch when !literalPath && originalPathSwitch.Equals("+", StringComparison.Ordinal):
                if (_setLocationHistory.RedoCount <= 0)
                {
                    throw new InvalidOperationException(SessionStateStrings.LocationRedoStackIsEmpty);
                }

                path = _setLocationHistory.Redo(this.CurrentLocation).Path;
                break;

            default:
                var pushPathInfo = GetNewPushPathInfo();
                _setLocationHistory.Push(pushPathInfo);
                break;
            }

            PSDriveInfo previousWorkingDrive = CurrentDrive;

            // First check to see if the path is a home path
            if (LocationGlobber.IsHomePath(path))
            {
                path = Globber.GetHomeRelativePath(path);
            }

            if (LocationGlobber.IsProviderDirectPath(path))
            {
                // The path is a provider-direct path so use the current
                // provider and its hidden drive but don't modify the path
                // at all.
                provider     = CurrentLocation.Provider;
                CurrentDrive = provider.HiddenDrive;
            }
            else if (LocationGlobber.IsProviderQualifiedPath(path, out providerId))
            {
                provider     = GetSingleProvider(providerId);
                CurrentDrive = provider.HiddenDrive;
            }
            else
            {
                // See if the path is a relative or absolute
                // path.
                if (Globber.IsAbsolutePath(path, out driveName))
                {
                    // Since the path is an absolute path
                    // we need to change the current working
                    // drive
                    PSDriveInfo newWorkingDrive = GetDrive(driveName);
                    CurrentDrive = newWorkingDrive;

                    // If the path is simply a colon-terminated drive,
                    // not a slash-terminated path to the root of a drive,
                    // set the path to the current working directory of that drive.
                    string colonTerminatedVolume = CurrentDrive.Name + ':';
                    if (CurrentDrive.VolumeSeparatedByColon && (path.Length == colonTerminatedVolume.Length))
                    {
                        path = Path.Combine(colonTerminatedVolume + Path.DirectorySeparatorChar, CurrentDrive.CurrentLocation);
                    }

                    // Now that the current working drive is set,
                    // process the rest of the path as a relative path.
                }
            }

            if (context == null)
            {
                context = new CmdletProviderContext(this.ExecutionContext);
            }

            if (CurrentDrive != null)
            {
                context.Drive = CurrentDrive;
            }

            CmdletProvider providerInstance = null;

            Collection <PathInfo> workingPath = null;

            try
            {
                workingPath =
                    Globber.GetGlobbedMonadPathsFromMonadPath(
                        path,
                        false,
                        context,
                        out providerInstance);
            }
            catch (LoopFlowException)
            {
                throw;
            }
            catch (PipelineStoppedException)
            {
                throw;
            }
            catch (ActionPreferenceStopException)
            {
                throw;
            }
            catch (Exception)
            {
                // Reset the drive to the previous drive and
                // then rethrow the error
                CurrentDrive = previousWorkingDrive;
                throw;
            }

            if (workingPath.Count == 0)
            {
                // Set the current working drive back to the previous
                // one in case it was changed.
                CurrentDrive = previousWorkingDrive;

                throw
                    new ItemNotFoundException(
                        path,
                        "PathNotFound",
                        SessionStateStrings.PathNotFound);
            }

            // We allow globbing the location as long as it only resolves a single container.
            bool foundContainer                     = false;
            bool pathIsContainer                    = false;
            bool pathIsProviderQualifiedPath        = false;
            bool currentPathisProviderQualifiedPath = false;

            for (int index = 0; index < workingPath.Count; ++index)
            {
                CmdletProviderContext normalizePathContext =
                    new CmdletProviderContext(context);

                PathInfo resolvedPath = workingPath[index];
                string   currentPath  = path;
                try
                {
                    string providerName = null;
                    currentPathisProviderQualifiedPath = LocationGlobber.IsProviderQualifiedPath(resolvedPath.Path, out providerName);
                    if (currentPathisProviderQualifiedPath)
                    {
                        // The path should be the provider-qualified path without the provider ID
                        // or ::
                        string providerInternalPath = LocationGlobber.RemoveProviderQualifier(resolvedPath.Path);

                        try
                        {
                            currentPath = NormalizeRelativePath(GetSingleProvider(providerName), providerInternalPath, string.Empty, normalizePathContext);
                        }
                        catch (NotSupportedException)
                        {
                            // Since the provider does not support normalizing the path, just
                            // use the path we currently have.
                        }
                        catch (LoopFlowException)
                        {
                            throw;
                        }
                        catch (PipelineStoppedException)
                        {
                            throw;
                        }
                        catch (ActionPreferenceStopException)
                        {
                            throw;
                        }
                        catch (Exception)
                        {
                            // Reset the drive to the previous drive and
                            // then rethrow the error
                            CurrentDrive = previousWorkingDrive;
                            throw;
                        }
                    }
                    else
                    {
                        try
                        {
                            currentPath = NormalizeRelativePath(resolvedPath.Path, CurrentDrive.Root, normalizePathContext);
                        }
                        catch (NotSupportedException)
                        {
                            // Since the provider does not support normalizing the path, just
                            // use the path we currently have.
                        }
                        catch (LoopFlowException)
                        {
                            throw;
                        }
                        catch (PipelineStoppedException)
                        {
                            throw;
                        }
                        catch (ActionPreferenceStopException)
                        {
                            throw;
                        }
                        catch (Exception)
                        {
                            // Reset the drive to the previous drive and
                            // then rethrow the error
                            CurrentDrive = previousWorkingDrive;
                            throw;
                        }
                    }

                    // Now see if there was errors while normalizing the path
                    if (normalizePathContext.HasErrors())
                    {
                        // Set the current working drive back to the previous
                        // one in case it was changed.
                        CurrentDrive = previousWorkingDrive;

                        normalizePathContext.ThrowFirstErrorOrDoNothing();
                    }
                }
                finally
                {
                    normalizePathContext.RemoveStopReferral();
                }

                bool isContainer = false;

                CmdletProviderContext itemContainerContext =
                    new CmdletProviderContext(context);
                itemContainerContext.SuppressWildcardExpansion = true;

                try
                {
                    isContainer =
                        IsItemContainer(
                            resolvedPath.Path,
                            itemContainerContext);

                    if (itemContainerContext.HasErrors())
                    {
                        // Set the current working drive back to the previous
                        // one in case it was changed.
                        CurrentDrive = previousWorkingDrive;

                        itemContainerContext.ThrowFirstErrorOrDoNothing();
                    }
                }
                catch (NotSupportedException)
                {
                    if (currentPath.Length == 0)
                    {
                        // Treat this as a container because providers that only
                        // support the ContainerCmdletProvider interface are really
                        // containers at their root.
                        isContainer = true;
                    }
                }
                finally
                {
                    itemContainerContext.RemoveStopReferral();
                }

                if (isContainer)
                {
                    if (foundContainer)
                    {
                        // The path resolved to more than one container
                        // Set the current working drive back to the previous
                        // one in case it was changed.
                        CurrentDrive = previousWorkingDrive;

                        throw
                            PSTraceSource.NewArgumentException(
                                "path",
                                SessionStateStrings.PathResolvedToMultiple,
                                originalPath);
                    }
                    else
                    {
                        // Set the path to use
                        path = currentPath;

                        // Mark it as a container
                        pathIsContainer = true;

                        // Mark whether or not it was provider-qualified
                        pathIsProviderQualifiedPath = currentPathisProviderQualifiedPath;

                        // Mark that we have already found one container. Finding additional
                        // should be an error
                        foundContainer = true;
                    }
                }
            }

            if (pathIsContainer)
            {
                // Remove the root slash since it is implied that the
                // current working directory is relative to the root.
                if (!LocationGlobber.IsProviderDirectPath(path) &&
                    path.StartsWith(StringLiterals.DefaultPathSeparator) &&
                    !pathIsProviderQualifiedPath)
                {
                    path = path.Substring(1);
                }

                s_tracer.WriteLine(
                    "New working path = {0}",
                    path);

                CurrentDrive.CurrentLocation = path;
            }
            else
            {
                // Set the current working drive back to the previous
                // one in case it was changed.
                CurrentDrive = previousWorkingDrive;

                throw
                    new ItemNotFoundException(
                        originalPath,
                        "PathNotFound",
                        SessionStateStrings.PathNotFound);
            }

            // Now make sure the current drive is set in the provider's
            // current working drive hashtable
            ProvidersCurrentWorkingDrive[CurrentDrive.Provider] =
                CurrentDrive;

            // Set the $PWD variable to the new location
            this.SetVariable(SpecialVariables.PWDVarPath, this.CurrentLocation, false, true, CommandOrigin.Internal);

            // If an action has been defined for location changes, invoke it now.
            if (PublicSessionState.InvokeCommand.LocationChangedAction != null)
            {
                var eventArgs = new LocationChangedEventArgs(PublicSessionState, current, CurrentLocation);
                PublicSessionState.InvokeCommand.LocationChangedAction.Invoke(ExecutionContext.CurrentRunspace, eventArgs);
                s_tracer.WriteLine("Invoked LocationChangedAction");
            }

            return(this.CurrentLocation);
        }
        /// <summary>
        /// Runs the application.
        /// </summary>
        /// <param name="args">Arguments.</param>
        /// <param name="appRoot">Application root folder</param>
        /// <returns>0 on success.</returns>
        public int Run(string[] args, string appRoot = null)
        {
            var console = new CakeConsole();
            var logger  = new SafeCakeLog(console);
            var engine  = new CakeEngine(logger);

            ICakePlatform          platform    = new CakePlatform();
            ICakeRuntime           runtime     = new CakeRuntime();
            IFileSystem            fileSystem  = new FileSystem();
            MutableCakeEnvironment environment = new MutableCakeEnvironment(platform, runtime, appRoot);
            IGlobber globber = new Globber(fileSystem, environment);

            environment.Initialize(globber);
            IProcessRunner processRunner   = new ProcessRunner(environment, logger);
            IRegistry      windowsRegistry = new WindowsRegistry();
            // Parse options.
            var         argumentParser = new ArgumentParser(logger, fileSystem);
            CakeOptions options        = argumentParser.Parse(args);

            Debug.Assert(options != null);
            CakeConfigurationProvider configProvider = new CakeConfigurationProvider(fileSystem, environment);
            ICakeConfiguration        configuration  = configProvider.CreateConfiguration(environment.ApplicationRoot, options.Arguments);
            IToolRepository           toolRepo       = new ToolRepository(environment);
            IToolResolutionStrategy   toolStrategy   = new ToolResolutionStrategy(fileSystem, environment, globber, configuration);
            IToolLocator locator     = new ToolLocator(environment, toolRepo, toolStrategy);
            IToolLocator toolLocator = new ToolLocator(environment, toolRepo, toolStrategy);

            logger.SetVerbosity(options.Verbosity);
            CodeCakeBuildTypeDescriptor choosenBuild;

            if (!AvailableBuilds.TryGetValue(options.Script, out choosenBuild))
            {
                logger.Error("Build script '{0}' not found.", options.Script);
                return(-1);
            }

            ICakeArguments arguments = new CakeArguments(options.Arguments);

            var context = new CakeContext(fileSystem, environment, globber, logger, arguments, processRunner, windowsRegistry, locator);

            // Copy the arguments from the options.

            // Set the working directory: the solution directory.
            environment.WorkingDirectory = new DirectoryPath(_solutionDirectory);

            // Adds additional paths from chosen build.
            foreach (var p in choosenBuild.AdditionnalPatternPaths)
            {
                environment.AddPath(p);
            }
            logger.Information("Path(s) added: " + string.Join(", ", environment.EnvironmentAddedPaths));
            logger.Information("Dynamic pattern path(s) added: " + string.Join(", ", environment.EnvironmentDynamicPaths));

            try
            {
                // Instanciates the script object.
                CodeCakeHost._injectedActualHost = new BuildScriptHost(engine, context);
                CodeCakeHost c = (CodeCakeHost)Activator.CreateInstance(choosenBuild.Type);

                var strategy = new DefaultExecutionStrategy(logger);
                var report   = engine.RunTargetAsync(context, strategy, context.Arguments.GetArgument("target") ?? "Default").GetAwaiter().GetResult();
                if (report != null && !report.IsEmpty)
                {
                    var printerReport = new CakeReportPrinter(console);
                    printerReport.Write(report);
                }
            }
            catch (CakeTerminateException ex)
            {
                switch (ex.Option)
                {
                case CakeTerminationOption.Error:
                    logger.Error("Termination with Error: '{0}'.", ex.Message);
                    return(-1);

                case CakeTerminationOption.Warning:
                    logger.Warning("Termination with Warning: '{0}'.", ex.Message);
                    break;

                default:
                    Debug.Assert(ex.Option == CakeTerminationOption.Success);
                    logger.Information("Termination with Success: '{0}'.", ex.Message);
                    break;
                }
            }
            catch (TargetInvocationException ex)
            {
                logger.Error("Error occurred: '{0}'.", ex.InnerException?.Message ?? ex.Message);
                return(-1);
            }
            catch (Exception ex)
            {
                logger.Error("Error occurred: '{0}'.", ex.Message);
                return(-1);
            }
            return(0);
        }
        } // SetLocation

        /// <summary>
        /// Changes the current working directory to the path specified
        /// </summary>
        ///
        /// <param name="path">
        /// The path of the new current working directory
        /// </param>
        ///
        /// <param name="context">
        /// The context the provider uses when performing the operation.
        /// </param>
        ///
        /// <returns>
        /// The PathInfo object representing the path of the location
        /// that was set.
        /// </returns>
        ///
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="path"/> is null.
        /// </exception>
        ///
        /// <exception cref="ArgumentException">
        /// If <paramref name="path"/> does not exist, is not a container, or
        /// resolved to multiple containers.
        /// </exception>
        ///
        /// <exception cref="ProviderNotFoundException">
        /// If <paramref name="path"/> refers to a provider that does not exist.
        /// </exception>
        ///
        /// <exception cref="DriveNotFoundException">
        /// If <paramref name="path"/> refers to a drive that does not exist.
        /// </exception>
        ///
        /// <exception cref="ProviderInvocationException">
        /// If the provider associated with <paramref name="path"/> threw an
        /// exception.
        /// </exception>
        ///
        /// <exception cref="ItemNotFoundException">
        /// If the <paramref name="path"/> could not be resolved.
        /// </exception>
        ///
        internal PathInfo SetLocation(string path, CmdletProviderContext context)
        {
            if (path == null)
            {
                throw PSTraceSource.NewArgumentNullException("path");
            }

            string       originalPath = path;
            string       driveName    = null;
            ProviderInfo provider     = null;
            string       providerId   = null;

            PSDriveInfo previousWorkingDrive = CurrentDrive;

            // First check to see if the path is a home path

            if (LocationGlobber.IsHomePath(path))
            {
                path = Globber.GetHomeRelativePath(path);
            }

            if (LocationGlobber.IsProviderDirectPath(path))
            {
                // The path is a provider-direct path so use the current
                // provider and its hidden drive but don't modify the path
                // at all.

                provider     = CurrentLocation.Provider;
                CurrentDrive = provider.HiddenDrive;
            }
            else if (LocationGlobber.IsProviderQualifiedPath(path, out providerId))
            {
                provider     = GetSingleProvider(providerId);
                CurrentDrive = provider.HiddenDrive;
            }
            else
            {
                // See if the path is a relative or absolute
                // path.

                if (Globber.IsAbsolutePath(path, out driveName))
                {
                    // Since the path is an absolute path
                    // we need to change the current working
                    // drive

                    PSDriveInfo newWorkingDrive = GetDrive(driveName);
                    CurrentDrive = newWorkingDrive;

                    // Now that the current working drive is set,
                    // process the rest of the path as a relative path.
                }
            }

            if (context == null)
            {
                context = new CmdletProviderContext(this.ExecutionContext);
            }

            if (CurrentDrive != null)
            {
                context.Drive = CurrentDrive;
            }

            CmdletProvider providerInstance = null;

            Collection <PathInfo> workingPath = null;

            try
            {
                workingPath =
                    Globber.GetGlobbedMonadPathsFromMonadPath(
                        path,
                        false,
                        context,
                        out providerInstance);
            }
            catch (LoopFlowException)
            {
                throw;
            }
            catch (PipelineStoppedException)
            {
                throw;
            }
            catch (ActionPreferenceStopException)
            {
                throw;
            }
            catch (Exception) // Catch-all OK, 3rd party callout
            {
                // Reset the drive to the previous drive and
                // then rethrow the error

                CurrentDrive = previousWorkingDrive;
                throw;
            }

            if (workingPath.Count == 0)
            {
                // Set the current working drive back to the previous
                // one in case it was changed.

                CurrentDrive = previousWorkingDrive;

                throw
                    new ItemNotFoundException(
                        path,
                        "PathNotFound",
                        SessionStateStrings.PathNotFound);
            }

            // We allow globbing the location as long as it only resolves a single container.

            bool foundContainer                     = false;
            bool pathIsContainer                    = false;
            bool pathIsProviderQualifiedPath        = false;
            bool currentPathisProviderQualifiedPath = false;

            for (int index = 0; index < workingPath.Count; ++index)
            {
                CmdletProviderContext normalizePathContext =
                    new CmdletProviderContext(context);

                PathInfo resolvedPath = workingPath[index];
                string   currentPath  = path;
                try
                {
                    string providerName = null;
                    currentPathisProviderQualifiedPath = LocationGlobber.IsProviderQualifiedPath(resolvedPath.Path, out providerName);
                    if (currentPathisProviderQualifiedPath)
                    {
                        // The path should be the provider-qualified path without the provider ID
                        // or ::

                        string providerInternalPath = LocationGlobber.RemoveProviderQualifier(resolvedPath.Path);

                        try
                        {
                            currentPath = NormalizeRelativePath(GetSingleProvider(providerName), providerInternalPath, String.Empty, normalizePathContext);
                        }
                        catch (NotSupportedException)
                        {
                            // Since the provider does not support normalizing the path, just
                            // use the path we currently have.
                        }
                        catch (LoopFlowException)
                        {
                            throw;
                        }
                        catch (PipelineStoppedException)
                        {
                            throw;
                        }
                        catch (ActionPreferenceStopException)
                        {
                            throw;
                        }
                        catch (Exception) // Catch-all OK, 3rd party callout
                        {
                            // Reset the drive to the previous drive and
                            // then rethrow the error

                            CurrentDrive = previousWorkingDrive;
                            throw;
                        }
                    }
                    else
                    {
                        try
                        {
                            currentPath = NormalizeRelativePath(resolvedPath.Path, CurrentDrive.Root, normalizePathContext);
                        }
                        catch (NotSupportedException)
                        {
                            // Since the provider does not support normalizing the path, just
                            // use the path we currently have.
                        }
                        catch (LoopFlowException)
                        {
                            throw;
                        }
                        catch (PipelineStoppedException)
                        {
                            throw;
                        }
                        catch (ActionPreferenceStopException)
                        {
                            throw;
                        }
                        catch (Exception) // Catch-all OK, 3rd party callout
                        {
                            // Reset the drive to the previous drive and
                            // then rethrow the error

                            CurrentDrive = previousWorkingDrive;
                            throw;
                        }
                    }

                    // Now see if there was errors while normalizing the path

                    if (normalizePathContext.HasErrors())
                    {
                        // Set the current working drive back to the previous
                        // one in case it was changed.

                        CurrentDrive = previousWorkingDrive;

                        normalizePathContext.ThrowFirstErrorOrDoNothing();
                    }
                }
                finally
                {
                    normalizePathContext.RemoveStopReferral();
                }

                // Check to see if the path is a container

                bool isContainer = false;

                CmdletProviderContext itemContainerContext =
                    new CmdletProviderContext(context);
                itemContainerContext.SuppressWildcardExpansion = true;

                try
                {
                    isContainer =
                        IsItemContainer(
                            resolvedPath.Path,
                            itemContainerContext);

                    if (itemContainerContext.HasErrors())
                    {
                        // Set the current working drive back to the previous
                        // one in case it was changed.

                        CurrentDrive = previousWorkingDrive;

                        itemContainerContext.ThrowFirstErrorOrDoNothing();
                    }
                }
                catch (NotSupportedException)
                {
                    if (currentPath.Length == 0)
                    {
                        // Treat this as a container because providers that only
                        // support the ContainerCmdletProvider interface are really
                        // containers at their root.

                        isContainer = true;
                    }
                }
                finally
                {
                    itemContainerContext.RemoveStopReferral();
                }

                if (isContainer)
                {
                    if (foundContainer)
                    {
                        // The path resolved to more than one container

                        // Set the current working drive back to the previous
                        // one in case it was changed.

                        CurrentDrive = previousWorkingDrive;

                        throw
                            PSTraceSource.NewArgumentException(
                                "path",
                                SessionStateStrings.PathResolvedToMultiple,
                                originalPath);
                    }
                    else
                    {
                        // Set the path to use
                        path = currentPath;

                        // Mark it as a container
                        pathIsContainer = true;

                        // Mark whether or not it was provider-qualified
                        pathIsProviderQualifiedPath = currentPathisProviderQualifiedPath;

                        // Mark that we have already found one container. Finding additional
                        // should be an error
                        foundContainer = true;
                    }
                }
            }

            if (pathIsContainer)
            {
                // Remove the root slash since it is implied that the
                // current working directory is relative to the root.

                if (!LocationGlobber.IsProviderDirectPath(path) &&
                    path.StartsWith(StringLiterals.DefaultPathSeparatorString, StringComparison.CurrentCulture) &&
                    !pathIsProviderQualifiedPath)
                {
                    path = path.Substring(1);
                }

                s_tracer.WriteLine(
                    "New working path = {0}",
                    path);

                CurrentDrive.CurrentLocation = path;
            }
            else
            {
                // Set the current working drive back to the previous
                // one in case it was changed.

                CurrentDrive = previousWorkingDrive;

                throw
                    new ItemNotFoundException(
                        originalPath,
                        "PathNotFound",
                        SessionStateStrings.PathNotFound);
            }

            // Now make sure the current drive is set in the provider's
            // current working drive hashtable

            ProvidersCurrentWorkingDrive[CurrentDrive.Provider] =
                CurrentDrive;

            // Set the $PWD variable to the new location

            this.SetVariable(SpecialVariables.PWDVarPath, this.CurrentLocation, false, true, CommandOrigin.Internal);
            return(this.CurrentLocation);
        } // SetLocation
        /// <summary>
        /// Runs the application.
        /// </summary>
        /// <param name="args">Arguments.</param>
        /// <returns>0 on success.</returns>
        public int Run( string[] args )
        {
            var console = new CakeConsole();
            var logger = new SafeCakeLog( console );
            var engine = new CakeEngine( logger );

            ICakePlatform platform = new CakePlatform();
            ICakeRuntime runtime = new CakeRuntime();
            IFileSystem fileSystem = new FileSystem();
            MutableCakeEnvironment environment = new MutableCakeEnvironment( platform, runtime );
            IGlobber globber = new Globber( fileSystem, environment );
            environment.Initialize( globber );
            IProcessRunner processRunner = new ProcessRunner( environment, logger );
            IRegistry windowsRegistry = new WindowsRegistry();
            // Parse options.
            var argumentParser = new ArgumentParser( logger, fileSystem );
            CakeOptions options = argumentParser.Parse( args );
            Debug.Assert( options != null );
            CakeConfigurationProvider configProvider = new CakeConfigurationProvider( fileSystem, environment );
            ICakeConfiguration configuration = configProvider.CreateConfiguration( environment.ApplicationRoot, options.Arguments );
            IToolRepository toolRepo = new ToolRepository( environment );
            IToolResolutionStrategy toolStrategy = new ToolResolutionStrategy( fileSystem, environment, globber, configuration );
            IToolLocator locator = new ToolLocator( environment, toolRepo, toolStrategy );
            IToolLocator toolLocator = new ToolLocator( environment, toolRepo, toolStrategy  );
            logger.SetVerbosity( options.Verbosity );
            CodeCakeBuildTypeDescriptor choosenBuild;
            if( !AvailableBuilds.TryGetValue( options.Script, out choosenBuild ) )
            {
                logger.Error( "Build script '{0}' not found.", options.Script );
                return -1;
            }

            ICakeArguments arguments = new CakeArguments(options.Arguments);

            var context = new CakeContext( fileSystem, environment, globber, logger, arguments, processRunner, windowsRegistry, locator );

            // Copy the arguments from the options.

            // Set the working directory: the solution directory.
            environment.WorkingDirectory = new DirectoryPath( _solutionDirectory );

            // Adds additional paths from chosen build.
            foreach( var p in choosenBuild.AdditionnalPatternPaths )
            {
                environment.AddPath( p );
            }
            logger.Information( "Path(s) added: " + string.Join( ", ", environment.EnvironmentAddedPaths ) );
            logger.Information( "Dynamic pattern path(s) added: " + string.Join( ", ", environment.EnvironmentDynamicPaths ) );

            try
            {
                // Instanciates the script object.
                CodeCakeHost._injectedActualHost = new BuildScriptHost( engine, context );
                CodeCakeHost c = (CodeCakeHost)Activator.CreateInstance( choosenBuild.Type );

                var strategy = new DefaultExecutionStrategy( logger );
                var report = engine.RunTarget( context, strategy, context.Arguments.GetArgument( "target" ) ?? "Default" );
                if( report != null && !report.IsEmpty )
                {
                    var printerReport = new CakeReportPrinter( console );
                    printerReport.Write( report );
                }
            }
            catch( CakeTerminateException ex )
            {
                switch( ex.Option )
                {
                    case CakeTerminationOption.Error:
                        logger.Error( "Termination with Error: '{0}'.", ex.Message );
                        return -1;
                    case CakeTerminationOption.Warning:
                        logger.Warning( "Termination with Warning: '{0}'.", ex.Message );
                        break;
                    default:
                        Debug.Assert( ex.Option == CakeTerminationOption.Success );
                        logger.Information( "Termination with Success: '{0}'.", ex.Message );
                        break;
                }
            }
            catch( TargetInvocationException ex )
            {
                logger.Error( "Error occurred: '{0}'.", ex.InnerException?.Message ?? ex.Message );
                return -1;
            }
            catch( Exception ex )
            {
                logger.Error( "Error occurred: '{0}'.", ex.Message );
                return -1;
            }
            return 0;
        }
Beispiel #23
0
        /// <summary>
        /// Determines if the specified path is the current working directory
        /// or a parent of the current working directory.
        /// </summary>
        /// <param name="path">
        /// A monad namespace absolute or relative path.
        /// </param>
        /// <param name="context">
        /// The context the provider uses when performing the operation.
        /// </param>
        /// <returns>
        /// true, if the path is the current working directory or a parent of the current
        /// working directory. false, otherwise.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="path"/> is null.
        /// </exception>
        /// <exception cref="ProviderNotFoundException">
        /// If the path is a provider-qualified path for a provider that is
        /// not loaded into the system.
        /// </exception>
        /// <exception cref="DriveNotFoundException">
        /// If the <paramref name="path"/> refers to a drive that could not be found.
        /// </exception>
        /// <exception cref="ProviderInvocationException">
        /// If the provider used to build the path threw an exception.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// If the provider that the <paramref name="path"/> represents is not a NavigationCmdletProvider
        /// or ContainerCmdletProvider.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the <paramref name="path"/> starts with "~" and the home location is not set for
        /// the provider.
        /// </exception>
        /// <exception cref="ProviderInvocationException">
        /// If the provider specified by <paramref name="providerId"/> threw an
        /// exception when its GetParentPath or MakePath was called while
        /// processing the <paramref name="path"/>.
        /// </exception>
        internal bool IsCurrentLocationOrAncestor(string path, CmdletProviderContext context)
        {
            bool result = false;

            if (path == null)
            {
                throw PSTraceSource.NewArgumentNullException("path");
            }

            PSDriveInfo  drive    = null;
            ProviderInfo provider = null;

            string providerSpecificPath =
                Globber.GetProviderPath(
                    path,
                    context,
                    out provider,
                    out drive);

            if (drive != null)
            {
                s_tracer.WriteLine("Tracing drive");
                drive.Trace();
            }

            Dbg.Diagnostics.Assert(
                providerSpecificPath != null,
                "There should always be a way to generate a provider path for a " +
                "given path");

            if (drive != null)
            {
                context.Drive = drive;
            }

            // Check to see if the path that was specified is within the current
            // working drive
            if (drive == CurrentDrive)
            {
                // The path needs to be normalized to get rid of relative path tokens
                // so they don't interfere with our path comparisons below
                CmdletProviderContext normalizePathContext
                    = new CmdletProviderContext(context);

                try
                {
                    providerSpecificPath = NormalizeRelativePath(path, null, normalizePathContext);
                }
                catch (NotSupportedException)
                {
                    // Since the provider does not support normalizing the path, just
                    // use the path we currently have.
                }
                catch (LoopFlowException)
                {
                    throw;
                }
                catch (PipelineStoppedException)
                {
                    throw;
                }
                catch (ActionPreferenceStopException)
                {
                    throw;
                }
                finally
                {
                    normalizePathContext.RemoveStopReferral();
                }

                if (normalizePathContext.HasErrors())
                {
                    normalizePathContext.ThrowFirstErrorOrDoNothing();
                }

                s_tracer.WriteLine("Provider path = {0}", providerSpecificPath);

                // Get the current working directory provider specific path
                PSDriveInfo  currentWorkingDrive  = null;
                ProviderInfo currentDriveProvider = null;

                string currentWorkingPath =
                    Globber.GetProviderPath(
                        ".",
                        context,
                        out currentDriveProvider,
                        out currentWorkingDrive);

                Dbg.Diagnostics.Assert(
                    currentWorkingDrive == CurrentDrive,
                    "The current working drive should be the CurrentDrive.");

                s_tracer.WriteLine(
                    "Current working path = {0}",
                    currentWorkingPath);

                // See if the path is the current working directory or a parent
                // of the current working directory
                s_tracer.WriteLine(
                    "Comparing {0} to {1}",
                    providerSpecificPath,
                    currentWorkingPath);

                if (String.Compare(providerSpecificPath, currentWorkingPath, StringComparison.CurrentCultureIgnoreCase) == 0)
                {
                    // The path is the current working directory so
                    // return true
                    s_tracer.WriteLine("The path is the current working directory");

                    result = true;
                }
                else
                {
                    // Check to see if the specified path is a parent
                    // of the current working directory
                    string lockedDirectory = currentWorkingPath;

                    while (lockedDirectory.Length > 0)
                    {
                        // We need to allow the provider to go as far up the tree
                        // as it can even if that means it has to traverse higher
                        // than the mount point for this drive. That is
                        // why we are passing the empty string as the root here.
                        lockedDirectory =
                            GetParentPath(
                                drive.Provider,
                                lockedDirectory,
                                String.Empty,
                                context);

                        s_tracer.WriteLine(
                            "Comparing {0} to {1}",
                            lockedDirectory,
                            providerSpecificPath);

                        if (String.Compare(lockedDirectory, providerSpecificPath, StringComparison.CurrentCultureIgnoreCase) == 0)
                        {
                            // The path is a parent of the current working
                            // directory
                            s_tracer.WriteLine(
                                "The path is a parent of the current working directory: {0}",
                                lockedDirectory);

                            result = true;
                            break;
                        }
                    }
                }
            }
            else
            {
                s_tracer.WriteLine("Drives are not the same");
            }

            return(result);
        }
Beispiel #24
0
        public int Sign
        (
            CommandOption configFile,
            CommandOption inputFile,
            CommandOption baseDirectory,
            CommandOption outputFile,
            CommandOption fileList,
            CommandOption clientSecret,
            CommandOption username,
            CommandOption name,
            CommandOption description,
            CommandOption descriptionUrl,
            CommandOption maxConcurrency
        )
        {
            try
            {
                // verify required parameters
                if (!configFile.HasValue())
                {
                    signCommandLineApplication.Error.WriteLine("--config parameter is required");
                    return(EXIT_CODES.INVALID_OPTIONS);
                }

                if (!inputFile.HasValue())
                {
                    signCommandLineApplication.Error.WriteLine("--input parameter is required");
                    return(EXIT_CODES.INVALID_OPTIONS);
                }

                if (!name.HasValue())
                {
                    signCommandLineApplication.Error.WriteLine("--name parameter is required");
                    return(EXIT_CODES.INVALID_OPTIONS);
                }

                if (!maxConcurrency.HasValue())
                {
                    maxConcurrency.Values.Add("4"); // default to 4
                }

                if (baseDirectory.HasValue())
                {
                    // Make sure this is rooted
                    if (!Path.IsPathRooted(baseDirectory.Value()))
                    {
                        signCommandLineApplication.Error.WriteLine("--directory parameter must be rooted if specified");
                        return(EXIT_CODES.INVALID_OPTIONS);
                    }
                }

                if (!baseDirectory.HasValue())
                {
                    baseDirectory.Values.Add(Environment.CurrentDirectory);
                }

                List <FileInfo> inputFiles;
                // If we're going to glob, we can't be fully rooted currently (fix me later)

                var isGlob = inputFile.Value().Contains('*');

                if (isGlob)
                {
                    if (Path.IsPathRooted(inputFile.Value()))
                    {
                        signCommandLineApplication.Error.WriteLine("--input parameter cannot be rooted when using a glob. Use a path relative to the working directory");
                        return(EXIT_CODES.INVALID_OPTIONS);
                    }

                    inputFiles = Globber.GetFiles(new DirectoryInfo(baseDirectory.Value()), inputFile.Value())
                                 .ToList();
                }
                else
                {
                    inputFiles = new List <FileInfo>
                    {
                        new FileInfo(ExpandFilePath(inputFile.Value()))
                    };
                }



                var builder = new ConfigurationBuilder()
                              .AddJsonFile(ExpandFilePath(configFile.Value()))
                              .AddEnvironmentVariables();

                var configuration = builder.Build();


                Func <Task <string> > getAccessToken;


                var authority = $"{configuration["SignClient:AzureAd:AADInstance"]}{configuration["SignClient:AzureAd:TenantId"]}";

                var clientId   = configuration["SignClient:AzureAd:ClientId"];
                var resourceId = configuration["SignClient:Service:ResourceId"];

                // See if we have a Username option
                if (username.HasValue())
                {
                    // ROPC flow
                    var pca = PublicClientApplicationBuilder.Create(clientId)
                              .WithAuthority(authority)
                              .Build();

                    var secret = new NetworkCredential("", clientSecret.Value()).SecurePassword;

                    getAccessToken = async() =>
                    {
                        var tokenResult = await pca.AcquireTokenByUsernamePassword(new[] { $"{resourceId}/user_impersonation" }, username.Value(), secret).ExecuteAsync();

                        return(tokenResult.AccessToken);
                    };
                }
                else
                {
                    var context = ConfidentialClientApplicationBuilder.Create(clientId)
                                  .WithAuthority(authority)
                                  .WithClientSecret(clientSecret.Value())
                                  .Build();

                    getAccessToken = async() =>
                    {
                        // Client credential flow
                        var res = await context.AcquireTokenForClient(new[] { $"{resourceId}/.default" }).ExecuteAsync();

                        return(res.AccessToken);
                    };
                }

                // Setup Refit
                var settings = new RefitSettings
                {
                    AuthorizationHeaderValueGetter = getAccessToken
                };


                var client = RestService.For <ISignService>(configuration["SignClient:Service:Url"], settings);
                client.Client.Timeout = Timeout.InfiniteTimeSpan; // TODO: Make configurable on command line

                // var max concurrency
                if (!int.TryParse(maxConcurrency.Value(), out var maxC) || maxC < 1)
                {
                    signCommandLineApplication.Error.WriteLine("--maxConcurrency parameter is not valid");
                    return(EXIT_CODES.INVALID_OPTIONS);
                }

                if (inputFiles.Count == 0)
                {
                    signCommandLineApplication.Error.WriteLine("No inputs found to sign.");
                    return(EXIT_CODES.NO_INPUTS_FOUND);
                }

                Parallel.ForEach(inputFiles, new ParallelOptions {
                    MaxDegreeOfParallelism = maxC
                }, input =>
                {
                    FileInfo output;

                    var sw = Stopwatch.StartNew();

                    // Special case if there's only one input file and the output has a value, treat it as a file
                    if (inputFiles.Count == 1 && outputFile.HasValue())
                    {
                        // See if it has a file extension and if not, treat as a directory and use the input file name
                        var outFileValue = outputFile.Value();
                        if (Path.HasExtension(outFileValue))
                        {
                            output = new FileInfo(ExpandFilePath(outputFile.Value()));
                        }
                        else
                        {
                            output = new FileInfo(Path.Combine(ExpandFilePath(outFileValue), inputFiles[0].Name));
                        }
                    }
                    else
                    {
                        // if the output is specified, treat it as a directory, if not, overwrite the current file
                        if (!outputFile.HasValue())
                        {
                            output = new FileInfo(input.FullName);
                        }
                        else
                        {
                            var relative = Path.GetRelativePath(baseDirectory.Value(), input.FullName);

                            var basePath = Path.IsPathRooted(outputFile.Value()) ?
                                           outputFile.Value() :
                                           $"{baseDirectory.Value()}{Path.DirectorySeparatorChar}{outputFile.Value()}";

                            var fullOutput = Path.Combine(basePath, relative);

                            output = new FileInfo(fullOutput);
                        }
                    }

                    // Ensure the output directory exists
                    Directory.CreateDirectory(output.DirectoryName);

                    // Do action

                    HttpResponseMessage response;

                    signCommandLineApplication.Out.WriteLine($"Submitting '{input.FullName}' for signing.");

                    response = client.SignFile(input,
                                               fileList.HasValue() ? new FileInfo(ExpandFilePath(fileList.Value())) : null,
                                               HashMode.Sha256,
                                               name.Value(),
                                               description.Value(),
                                               descriptionUrl.Value()).Result;

                    // Check response

                    if (!response.IsSuccessStatusCode)
                    {
                        signCommandLineApplication.Error.WriteLine($"Error signing '{input.FullName}'");
                        signCommandLineApplication.Error.WriteLine($"Server returned non Ok response: {(int)response.StatusCode} {response.ReasonPhrase}");
                        response.EnsureSuccessStatusCode(); // force the throw to break out of the loop
                    }

                    var str = response.Content.ReadAsStreamAsync().Result;

                    // If we're replacing the file, make sure to the existing one first
                    using var fs = new FileStream(output.FullName, FileMode.Create);
                    str.CopyTo(fs);

                    signCommandLineApplication.Out.WriteLine($"Successfully signed '{output.FullName}' in {sw.ElapsedMilliseconds} ms");
                });
            }
            catch (AuthenticationException e)
            {
                signCommandLineApplication.Error.WriteLine(e.Message);
                return(EXIT_CODES.FAILED);
            }
            catch (Exception e)
            {
                signCommandLineApplication.Error.WriteLine("Exception: " + e);
                return(EXIT_CODES.FAILED);
            }

            return(EXIT_CODES.SUCCESS);

            string ExpandFilePath(string file)
            {
                if (!Path.IsPathRooted(file))
                {
                    return($"{baseDirectory.Value()}{Path.DirectorySeparatorChar}{file}");
                }
                return(file);
            }
        }
 /// <summary>Initializes a new instance of the <see cref="FileSystemEnvironment"/> class.</summary>
 public FileSystemEnvironment()
 {
     Globber          = new Globber(this);
     FS               = new FileSystem();
     WorkingDirectory = new DirectoryPath(System.IO.Directory.GetCurrentDirectory());
 }
Beispiel #26
0
        /// <summary>
        /// Runs the application.
        /// </summary>
        /// <param name="args">Arguments.</param>
        /// <param name="appRoot">Application root folder</param>
        /// <returns>The result of the run.</returns>
        public async Task <RunResult> RunAsync(IEnumerable <string> args, string appRoot = null)
        {
            var console = new CakeConsole();
            var logger  = new SafeCakeLog(console);
            ICakeDataService dataService = new CodeCakeDataService();
            var engine = new CakeEngine(dataService, logger);

            ICakePlatform          platform    = new CakePlatform();
            ICakeRuntime           runtime     = new CakeRuntime();
            IFileSystem            fileSystem  = new FileSystem();
            MutableCakeEnvironment environment = new MutableCakeEnvironment(platform, runtime, appRoot);

            console.SupportAnsiEscapeCodes = AnsiDetector.SupportsAnsi(environment);

            IGlobber globber = new Globber(fileSystem, environment);

            IRegistry windowsRegistry = new WindowsRegistry();
            // Parse options.
            var         argumentParser = new ArgumentParser(logger, fileSystem);
            CakeOptions options        = argumentParser.Parse(args);

            Debug.Assert(options != null);
            CakeConfigurationProvider configProvider = new CakeConfigurationProvider(fileSystem, environment);
            ICakeConfiguration        configuration  = configProvider.CreateConfiguration(environment.ApplicationRoot, options.Arguments);
            IToolRepository           toolRepo       = new ToolRepository(environment);
            IToolResolutionStrategy   toolStrategy   = new ToolResolutionStrategy(fileSystem, environment, globber, configuration, logger);
            IToolLocator   locator       = new ToolLocator(environment, toolRepo, toolStrategy);
            IToolLocator   toolLocator   = new ToolLocator(environment, toolRepo, toolStrategy);
            IProcessRunner processRunner = new ProcessRunner(fileSystem, environment, logger, toolLocator, configuration);

            logger.SetVerbosity(options.Verbosity);
            ICakeArguments arguments = new CakeArguments(options.Arguments);
            var            context   = new CakeContext(
                fileSystem,
                environment,
                globber,
                logger,
                arguments,
                processRunner,
                windowsRegistry,
                locator,
                dataService,
                configuration);

            CodeCakeBuildTypeDescriptor choosenBuild;

            if (!AvailableBuilds.TryGetValue(options.Script, out choosenBuild))
            {
                logger.Error("Build script '{0}' not found.", options.Script);
                return(new RunResult(-1, context.InteractiveMode()));
            }

            // Set the working directory: the solution directory.
            logger.Information($"Working in Solution directory: '{_solutionDirectory}'.");
            environment.WorkingDirectory = new DirectoryPath(_solutionDirectory);

            try
            {
                SetEnvironmentVariablesFromCodeCakeBuilderKeyVault(logger, context);

                // Instantiates the script object.
                CodeCakeHost._injectedActualHost = new BuildScriptHost(engine, context);
                CodeCakeHost c = (CodeCakeHost)Activator.CreateInstance(choosenBuild.Type);


                var target                  = context.Arguments.GetArgument("target") ?? "Default";
                var execSettings            = new ExecutionSettings().SetTarget(target);
                var exclusiveTargetOptional = context.Arguments.HasArgument("exclusiveOptional");
                var exclusiveTarget         = exclusiveTargetOptional | context.Arguments.HasArgument("exclusive");
                var strategy                = new CodeCakeExecutionStrategy(logger, exclusiveTarget ? target : null);
                if (exclusiveTargetOptional && !engine.Tasks.Any(t => t.Name == target))
                {
                    logger.Warning($"No task '{target}' defined. Since -exclusiveOptional is specified, nothing is done.");
                    return(new RunResult(0, context.InteractiveMode()));
                }
                var report = await engine.RunTargetAsync(context, strategy, execSettings);

                if (report != null && !report.IsEmpty)
                {
                    var printerReport = new CakeReportPrinter(console);
                    printerReport.Write(report);
                }
            }
            catch (CakeTerminateException ex)
            {
                switch (ex.Option)
                {
                case CakeTerminationOption.Error:
                    logger.Error("Termination with Error: '{0}'.", ex.Message);
                    return(new RunResult(-2, context.InteractiveMode()));

                case CakeTerminationOption.Warning:
                    logger.Warning("Termination with Warning: '{0}'.", ex.Message);
                    break;

                default:
                    Debug.Assert(ex.Option == CakeTerminationOption.Success);
                    logger.Information("Termination with Success: '{0}'.", ex.Message);
                    break;
                }
            }
            catch (TargetInvocationException ex)
            {
                logger.Error("Error occurred: '{0}'.", ex.InnerException?.Message ?? ex.Message);
                return(new RunResult(-3, context.InteractiveMode()));
            }
            catch (AggregateException ex)
            {
                logger.Error("Error occurred: '{0}'.", ex.Message);
                foreach (var e in ex.InnerExceptions)
                {
                    logger.Error("  -> '{0}'.", e.Message);
                }
                return(new RunResult(-4, context.InteractiveMode()));
            }
            catch (Exception ex)
            {
                logger.Error("Error occurred: '{0}'.", ex.Message);
                return(new RunResult(-5, context.InteractiveMode()));
            }
            return(new RunResult(0, context.InteractiveMode()));
        }
Beispiel #27
0
        public void ExpandPathTest(string baseDir, IEnumerable <string> patterns, PathExpansionEvaluator eval)
        {
            var result = Globber.ExpandPath(baseDir, patterns);

            Assert.True(eval(result));
        }