diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index b0eb411..3bf86a6 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -2,9 +2,9 @@ name: .NET on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] jobs: build: diff --git a/Git.Test/TestObject.fs b/Git.Test/TestObject.fs index e39dc92..7cbf4b0 100644 --- a/Git.Test/TestObject.fs +++ b/Git.Test/TestObject.fs @@ -79,3 +79,7 @@ module TestObject = for subStringEnd in 0 .. expected.Length - 1 do property expected.[0..subStringEnd] |> shouldEqual true + + expected.[0..subStringEnd].ToUpperInvariant () + |> property + |> shouldEqual true diff --git a/Git/Object.fs b/Git/Object.fs index 9e66dfa..58ff67d 100644 --- a/Git/Object.fs +++ b/Git/Object.fs @@ -21,17 +21,21 @@ type Object = module Object = /// Get the object hashes which match this start. let disambiguate (r : Repository) (startOfHash : string) : Hash list = + let objectDir = Repository.objectDir r + match startOfHash.Length with - | 0 -> (Repository.objectDir r).EnumerateFiles ("*", SearchOption.AllDirectories) + | 0 -> objectDir.EnumerateFiles ("*", SearchOption.AllDirectories) | 1 -> - (Repository.objectDir r).EnumerateFiles ("*", SearchOption.AllDirectories) - |> Seq.filter (fun i -> - i.Directory.Name.Length > 0 - && i.Directory.Name.[0] = startOfHash.[0] - ) + if r.IsCaseSensitive then + objectDir.EnumerateDirectories ("*", SearchOption.AllDirectories) + |> Seq.filter (fun dir -> dir.Name.[0] = startOfHash.[0]) + |> Seq.collect (fun dir -> dir.EnumerateFiles "*") + else + objectDir.EnumerateDirectories (sprintf "%c*" startOfHash.[0], SearchOption.AllDirectories) + |> Seq.collect (fun dir -> dir.EnumerateFiles "*") | 2 -> let subDir = - r.Fs.Path.Combine ((Repository.objectDir r).FullName, startOfHash) + r.Fs.Path.Combine (objectDir.FullName, startOfHash) |> r.Fs.DirectoryInfo.FromDirectoryName if subDir.Exists then @@ -40,15 +44,19 @@ module Object = Seq.empty | _ -> let prefix = startOfHash.Substring (0, 2) - let suffix = startOfHash.Substring (2, startOfHash.Length - 2) + let suffix = startOfHash.Substring 2 let subDir = - r.Fs.Path.Combine ((Repository.objectDir r).FullName, prefix) + r.Fs.Path.Combine (objectDir.FullName, prefix) |> r.Fs.DirectoryInfo.FromDirectoryName if subDir.Exists then - subDir.EnumerateFiles () - |> Seq.filter (fun i -> i.Name.StartsWith suffix) + if r.IsCaseSensitive then + subDir.EnumerateFiles () + |> Seq.filter (fun i -> i.Name.StartsWith suffix) + else + subDir.EnumerateFiles () + |> Seq.filter (fun i -> i.Name.StartsWith (suffix, true, null)) else Seq.empty diff --git a/Git/Repository.fs b/Git/Repository.fs index 9595ac5..3e1fb42 100644 --- a/Git/Repository.fs +++ b/Git/Repository.fs @@ -7,6 +7,7 @@ type Repository = private { Directory : IDirectoryInfo + IsCaseSensitive : bool } member this.Fs = this.Directory.FileSystem @@ -38,34 +39,37 @@ module Repository = output let make (dir : IDirectoryInfo) : Repository option = - if - dir.Exists - && dir.EnumerateDirectories () - |> Seq.map (fun i -> i.Name) - |> Seq.contains ".git" - then - Some { Directory = dir } + let fs = dir.FileSystem + let gitPath = fs.Path.Combine (dir.FullName, ".git") + + if dir.Exists && fs.Directory.Exists gitPath then + { + Directory = dir + IsCaseSensitive = + // Yes, if someone's made both `.git` and `.GIT` then we may think + // the filesystem is case insensitive. + not (fs.Directory.Exists (gitPath.ToUpperInvariant ())) + } + |> Some else None let init (dir : IDirectoryInfo) : Result = + match make dir with + | Some _ -> Error AlreadyGit + | None -> + if not dir.Exists then Error DirectoryDoesNotExist - elif - not - <| Seq.isEmpty (dir.EnumerateDirectories ".git") - then - Error AlreadyGit else - let r = { Directory = dir } - + // TODO do this atomically let gitDir = createSubdir dir ".git" let objectDir = createSubdir gitDir "objects" - let packDir = createSubdir objectDir "pack" - let infoDir = createSubdir objectDir "info" + let _packDir = createSubdir objectDir "pack" + let _infoDir = createSubdir objectDir "info" let refsDir = createSubdir gitDir "refs" - let headsDir = createSubdir refsDir "heads" - let tagsDir = createSubdir refsDir "tags" + let _headsDir = createSubdir refsDir "heads" + let _tagsDir = createSubdir refsDir "tags" - r |> Ok + make dir |> Option.get |> Ok