Skip to content

Commit

Permalink
add get log filepath, migrate tests to use get log filepath, add some…
Browse files Browse the repository at this point in the history
… todos
  • Loading branch information
tedim52 committed Aug 14, 2024
1 parent 3febce2 commit 7d3dd38
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 99 deletions.
16 changes: 8 additions & 8 deletions enclave-manager/api/typescript/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1512,11 +1512,11 @@ brace-expansion@^1.1.7:
concat-map "0.0.1"

braces@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
dependencies:
fill-range "^7.0.1"
fill-range "^7.1.1"

browserslist@^4.22.2:
version "4.22.2"
Expand Down Expand Up @@ -1791,10 +1791,10 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"

fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
fill-range@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
dependencies:
to-regex-range "^5.0.1"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,6 @@ import (
"time"
)

// this interface should support operations by the following clients:
// - logs aggregator
// - needs to know how to store files
//
// - log file manager
// - needs to know what to name the log files it creates
// - needs to log file paths to remove based on retention period, but also all of them
//
// - stream logs strategy
// - needs to know what
type LogFileLayout interface {
// GetLogFileLayoutFormat Returns a string representation the "format" that files are laid out in
// Formats are composed:
Expand All @@ -25,16 +15,11 @@ type LogFileLayout interface {
// - any other ascii text
GetLogFileLayoutFormat() string

// GetLogFilePath??
// GetLogFilePath gets the log file path for [serviceUuid] in [enclaveUuid] at [time]
GetLogFilePath(time time.Time, enclaveUuid, serviceUuid string) string

// GetLogFilePaths Retrieves a list of filepaths [filesystem] for [serviceUuid] in [enclaveUuid]
// GetLogFilePaths retrieves a list of filepaths [filesystem] for [serviceUuid] in [enclaveUuid]
// If [retentionPeriodIntervals] is set to -1, retrieves all filepaths from the currentTime till [retentionPeriod]
// If [retentionPeriodIntervals] is positive, retrieves all filepaths within the range [currentTime - retentionPeriod] and [currentTime - (retentionPeriodIntervals) * retentionPeriod]
GetLogFilePaths(filesystem volume_filesystem.VolumeFilesystem, retentionPeriod time.Duration, retentionPeriodIntervals int, enclaveUuid, serviceUuid string) ([]string, error)

// rename to "GetLogFilePaths"BasedOnRetentoin
// - should support getting log file paths within time period
// - theoretically should support getting all file log file paths
// following Philosophy of Software Design by John Ousterhoust - small interface, deep modules
//
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,25 @@ func NewPerWeekFileLayout(time logs_clock.LogsClock) *PerWeekFileLayout {
return &PerWeekFileLayout{time: time}
}

func (phf *PerWeekFileLayout) GetLogFileLayoutFormat() string {
func (pwf *PerWeekFileLayout) GetLogFileLayoutFormat() string {
return "/var/log/kurtosis/%%Y/%%V/{{ enclave_uuid }}/{{ service_uuid }}.json"
}

func (phf *PerWeekFileLayout) GetLogFilePath(time time.Time, enclaveUuid, serviceUuid string) string {
func (pwf *PerWeekFileLayout) GetLogFilePath(time time.Time, enclaveUuid, serviceUuid string) string {
year, week := time.ISOWeek()

formattedWeekNum := fmt.Sprintf("%02d", week)
return fmt.Sprintf(PerWeekFilePathFmtStr, volume_consts.LogsStorageDirpath, strconv.Itoa(year), formattedWeekNum, enclaveUuid, serviceUuid, volume_consts.Filetype)
}

// TODO: adjust to support getting log file paths beyond retention period
func (phf *PerWeekFileLayout) GetLogFilePaths(
func (pwf *PerWeekFileLayout) GetLogFilePaths(
filesystem volume_filesystem.VolumeFilesystem,
retentionPeriod time.Duration,
retentionPeriodIntervals int,
enclaveUuid, serviceUuid string) ([]string, error) {
var paths []string
currentTime := phf.time.Now()
currentTime := pwf.time.Now()

retentionPeriodInWeeks := DurationToWeeks(retentionPeriod)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package file_layout

import (
"fmt"
"github.com/kurtosis-tech/kurtosis/engine/server/engine/centralized_logs/client_implementations/persistent_volume/logs_clock"
"github.com/kurtosis-tech/kurtosis/engine/server/engine/centralized_logs/client_implementations/persistent_volume/volume_consts"
"github.com/kurtosis-tech/kurtosis/engine/server/engine/centralized_logs/client_implementations/persistent_volume/volume_filesystem"
"github.com/stretchr/testify/require"
"strconv"
"testing"
"time"
)
Expand All @@ -25,13 +22,16 @@ const (
func TestGetLogFilePaths(t *testing.T) {
filesystem := volume_filesystem.NewMockedVolumeFilesystem()

// ../week/enclave uuid/service uuid.json
week12filepath := getWeekFilepathStr(defaultYear, 12)
week13filepath := getWeekFilepathStr(defaultYear, 13)
week14filepath := getWeekFilepathStr(defaultYear, 14)
week15filepath := getWeekFilepathStr(defaultYear, 15)
week16filepath := getWeekFilepathStr(defaultYear, 16)
week17filepath := getWeekFilepathStr(defaultYear, 17)
currentWeek := 17
currentTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(currentTime)

week12filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 12, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week13filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 13, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week14filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 14, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week15filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 15, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week16filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 16, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week17filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 17, 0).Now(), testEnclaveUuid, testUserService1Uuid)

_, _ = filesystem.Create(week12filepath)
_, _ = filesystem.Create(week13filepath)
Expand All @@ -40,8 +40,6 @@ func TestGetLogFilePaths(t *testing.T) {
_, _ = filesystem.Create(week16filepath)
_, _ = filesystem.Create(week17filepath)

currentWeek := 17

expectedLogFilePaths := []string{
week13filepath,
week14filepath,
Expand All @@ -50,8 +48,6 @@ func TestGetLogFilePaths(t *testing.T) {
week17filepath,
}

mockTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(mockTime)
retentionPeriod := retentionPeriodInWeeksForTesting * oneWeekInHours
logFilePaths, err := fileLayout.GetLogFilePaths(filesystem, retentionPeriod, -1, testEnclaveUuid, testUserService1Uuid)

Expand All @@ -65,21 +61,23 @@ func TestGetLogFilePaths(t *testing.T) {
func TestGetLogFilePathsAcrossNewYear(t *testing.T) {
filesystem := volume_filesystem.NewMockedVolumeFilesystem()

currentWeek := 2
currentTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(currentTime)

// ../week/enclave uuid/service uuid.json
week50filepath := getWeekFilepathStr(defaultYear-1, 50)
week51filepath := getWeekFilepathStr(defaultYear-1, 51)
week52filepath := getWeekFilepathStr(defaultYear-1, 52)
week1filepath := getWeekFilepathStr(defaultYear, 1)
week2filepath := getWeekFilepathStr(defaultYear, 2)
week50filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear-1, 50, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week51filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear-1, 51, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week52filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear-1, 52, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week1filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 1, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week2filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 2, 0).Now(), testEnclaveUuid, testUserService1Uuid)

_, _ = filesystem.Create(week50filepath)
_, _ = filesystem.Create(week51filepath)
_, _ = filesystem.Create(week52filepath)
_, _ = filesystem.Create(week1filepath)
_, _ = filesystem.Create(week2filepath)

currentWeek := 2

expectedLogFilePaths := []string{
week50filepath,
week51filepath,
Expand All @@ -88,8 +86,6 @@ func TestGetLogFilePathsAcrossNewYear(t *testing.T) {
week2filepath,
}

mockTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(mockTime)
retentionPeriod := retentionPeriodInWeeksForTesting * oneWeekInHours
logFilePaths, err := fileLayout.GetLogFilePaths(filesystem, retentionPeriod, -1, testEnclaveUuid, testUserService1Uuid)

Expand All @@ -103,21 +99,23 @@ func TestGetLogFilePathsAcrossNewYear(t *testing.T) {
func TestGetLogFilePathsAcrossNewYearWith53Weeks(t *testing.T) {
filesystem := volume_filesystem.NewMockedVolumeFilesystem()

currentWeek := 3
currentTime := logs_clock.NewMockLogsClock(2016, currentWeek, 1)
fileLayout := NewPerWeekFileLayout(currentTime)

// According to ISOWeek, 2015 has 53 weeks
week52filepath := getWeekFilepathStr(2015, 52)
week53filepath := getWeekFilepathStr(2015, 53)
week1filepath := getWeekFilepathStr(2016, 1)
week2filepath := getWeekFilepathStr(2016, 2)
week3filepath := getWeekFilepathStr(2016, 3)
week52filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(2015, 52, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week53filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(2015, 53, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week1filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(2016, 1, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week2filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(2016, 2, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week3filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(2016, 3, 0).Now(), testEnclaveUuid, testUserService1Uuid)

_, _ = filesystem.Create(week52filepath)
_, _ = filesystem.Create(week53filepath)
_, _ = filesystem.Create(week1filepath)
_, _ = filesystem.Create(week2filepath)
_, _ = filesystem.Create(week3filepath)

currentWeek := 3

expectedLogFilePaths := []string{
week52filepath,
week53filepath,
Expand All @@ -126,8 +124,6 @@ func TestGetLogFilePathsAcrossNewYearWith53Weeks(t *testing.T) {
week3filepath,
}

mockTime := logs_clock.NewMockLogsClock(2016, currentWeek, 1)
fileLayout := NewPerWeekFileLayout(mockTime)
retentionPeriod := retentionPeriodInWeeksForTesting * oneWeekInHours
logFilePaths, err := fileLayout.GetLogFilePaths(filesystem, retentionPeriod, -1, testEnclaveUuid, testUserService1Uuid)

Expand All @@ -141,25 +137,24 @@ func TestGetLogFilePathsAcrossNewYearWith53Weeks(t *testing.T) {
func TestGetLogFilePathsWithDiffRetentionPeriod(t *testing.T) {
filesystem := volume_filesystem.NewMockedVolumeFilesystem()

currentWeek := 2
mockTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(mockTime)

// ../week/enclave uuid/service uuid.json
week52filepath := getWeekFilepathStr(defaultYear-1, 52)
week1filepath := getWeekFilepathStr(defaultYear, 1)
week2filepath := getWeekFilepathStr(defaultYear, 2)
week52filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear-1, 52, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week1filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 1, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week2filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 2, 0).Now(), testEnclaveUuid, testUserService1Uuid)

_, _ = filesystem.Create(week52filepath)
_, _ = filesystem.Create(week1filepath)
_, _ = filesystem.Create(week2filepath)

currentWeek := 2

expectedLogFilePaths := []string{
week52filepath,
week1filepath,
week2filepath,
}

mockTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(mockTime)
retentionPeriod := 3 * oneWeekInHours
logFilePaths, err := fileLayout.GetLogFilePaths(filesystem, retentionPeriod, -1, testEnclaveUuid, testUserService1Uuid)

Expand All @@ -173,10 +168,14 @@ func TestGetLogFilePathsWithDiffRetentionPeriod(t *testing.T) {
func TestGetLogFilePathsReturnsAllAvailableWeeks(t *testing.T) {
filesystem := volume_filesystem.NewMockedVolumeFilesystem()

currentWeek := 2
currentTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(currentTime)

// ../week/enclave uuid/service uuid.json
week52filepath := getWeekFilepathStr(defaultYear-1, 52)
week1filepath := getWeekFilepathStr(defaultYear, 1)
week2filepath := getWeekFilepathStr(defaultYear, 2)
week52filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear-1, 52, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week1filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 1, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week2filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 2, 0).Now(), testEnclaveUuid, testUserService1Uuid)

_, _ = filesystem.Create(week52filepath)
_, _ = filesystem.Create(week1filepath)
Expand All @@ -188,11 +187,6 @@ func TestGetLogFilePathsReturnsAllAvailableWeeks(t *testing.T) {
week1filepath,
week2filepath,
}

currentWeek := 2

mockTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(mockTime)
retentionPeriod := retentionPeriodInWeeksForTesting * oneWeekInHours
logFilePaths, err := fileLayout.GetLogFilePaths(filesystem, retentionPeriod, -1, testEnclaveUuid, testUserService1Uuid)

Expand All @@ -206,19 +200,18 @@ func TestGetLogFilePathsReturnsAllAvailableWeeks(t *testing.T) {
func TestGetLogFilePathsReturnsCorrectPathsIfWeeksMissingInBetween(t *testing.T) {
filesystem := volume_filesystem.NewMockedVolumeFilesystem()

currentWeek := 3
currentTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(currentTime)

// ../week/enclave uuid/service uuid.json
week52filepath := getWeekFilepathStr(defaultYear, 0)
week1filepath := getWeekFilepathStr(defaultYear, 1)
week3filepath := getWeekFilepathStr(defaultYear, 3)
week52filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 0, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week1filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 1, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week3filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 3, 0).Now(), testEnclaveUuid, testUserService1Uuid)

_, _ = filesystem.Create(week52filepath)
_, _ = filesystem.Create(week1filepath)
_, _ = filesystem.Create(week3filepath)

currentWeek := 3

mockTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(mockTime)
retentionPeriod := retentionPeriodInWeeksForTesting * oneWeekInHours
logFilePaths, err := fileLayout.GetLogFilePaths(filesystem, retentionPeriod, -1, testEnclaveUuid, testUserService1Uuid)

Expand All @@ -228,15 +221,16 @@ func TestGetLogFilePathsReturnsCorrectPathsIfWeeksMissingInBetween(t *testing.T)
}

func TestGetLogFilePathsReturnsCorrectPathsIfCurrentWeekHasNoLogsYet(t *testing.T) {
// currently in week 3
currentWeek := 3
mockTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)

filesystem := volume_filesystem.NewMockedVolumeFilesystem()

currentWeek := 3
currentTime := logs_clock.NewMockLogsClock(defaultYear, currentWeek, defaultDay)
fileLayout := NewPerWeekFileLayout(currentTime)

// ../week/enclave uuid/service uuid.json
week1filepath := getWeekFilepathStr(defaultYear, 1)
week2filepath := getWeekFilepathStr(defaultYear, 2)
week1filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 1, 0).Now(), testEnclaveUuid, testUserService1Uuid)
week2filepath := fileLayout.GetLogFilePath(logs_clock.NewMockLogsClock(defaultYear, 2, 0).Now(), testEnclaveUuid, testUserService1Uuid)

// no logs for week current week exist yet
_, _ = filesystem.Create(week1filepath)
Expand All @@ -248,7 +242,6 @@ func TestGetLogFilePathsReturnsCorrectPathsIfCurrentWeekHasNoLogsYet(t *testing.
week2filepath,
}

fileLayout := NewPerWeekFileLayout(mockTime)
retentionPeriod := retentionPeriodInWeeksForTesting * oneWeekInHours
logFilePaths, err := fileLayout.GetLogFilePaths(filesystem, retentionPeriod, -1, testEnclaveUuid, testUserService1Uuid)

Expand All @@ -258,9 +251,3 @@ func TestGetLogFilePathsReturnsCorrectPathsIfCurrentWeekHasNoLogsYet(t *testing.
require.Equal(t, filePath, logFilePaths[i])
}
}

func getWeekFilepathStr(year, week int) string {
// %02d to format week num with leading zeros so 1-9 are converted to 01-09 for %V format
formattedWeekNum := fmt.Sprintf("%02d", week)
return fmt.Sprintf(volume_consts.PerWeekFilePathFmtStr, volume_consts.LogsStorageDirpath, strconv.Itoa(year), formattedWeekNum, testEnclaveUuid, testUserService1Uuid, volume_consts.Filetype)
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ func (manager *LogFileManager) createSymlinkLogFile(targetLogFilePath, symlinkLo
return nil
}

// TODO: Implement a FilePath Builder to centralize log file path creation across the entire module
// creates a filepath of format /<filepath_base>/year/week/<enclave>/serviceIdentifier.<filetype>
func getFilepathStr(year, week int, enclaveUuid, serviceIdentifier string) string {
formattedWeekNum := fmt.Sprintf("%02d", week)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ func (strategy *PerWeekStreamLogsStrategy) StreamLogs(
// - The list of file paths is returned in order of oldest logs to most recent logs e.g. [ 03/80124/1234.json, /04/801234/1234.json, ...]
// - If a file path does not exist, the function with exits and returns whatever file paths were found
func (strategy *PerWeekStreamLogsStrategy) getLogFilePaths(filesystem volume_filesystem.VolumeFilesystem, retentionPeriodInWeeks int, enclaveUuid, serviceUuid string) ([]string, error) {
// TODO: embed FileLayout into StreamLogsStrategy interface
perWeekFileLayout := file_layout.NewPerWeekFileLayout(strategy.time)
retentionPeriod := time.Duration(retentionPeriodInWeeks) * oneWeek
return perWeekFileLayout.GetLogFilePaths(filesystem, retentionPeriod, -1, enclaveUuid, serviceUuid)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const (
defaultDay = 0 // sunday
)

// TODO: migrate GetLogFilePaths tests to FileLayout interface when it is fully merged
// for now, leave them duplicated so there's an extra layer of testing as the migration happens
func TestGetLogFilePaths(t *testing.T) {
filesystem := volume_filesystem.NewMockedVolumeFilesystem()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
// basepath/enclave uuid/service uuid <filetype>
PerFileFmtStr = "%s%s/%s%s"

// TODO: remove these from consts once PerWeekFileLayout is fully merged
// basepath /year/week
PerWeekDirPathStr = "%s%s/%s/"

Expand Down

0 comments on commit 7d3dd38

Please sign in to comment.