Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

cli: streamline autostart ux#2251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
johnstcn merged 14 commits intomainfromcj/1647/autostart-set-unset
Jun 13, 2022
Merged

Conversation

johnstcn
Copy link
Member

@johnstcnjohnstcn commentedJun 10, 2022
edited
Loading

This PR makes the following changes:

  • autostart enable|disable =>autostart set|unset
  • autostart enable now accepts a more natual schedule format:<time> <days-of-week> <location>
  • autostart show now shows configured timezone
  • 🎉 automatic timezone detection across mac, windows, linux 🎉

Fixes#1647

@johnstcnjohnstcn requested a review froma teamJune 10, 2022 17:21
@johnstcnjohnstcn marked this pull request as ready for reviewJune 10, 2022 17:21
@johnstcnjohnstcn self-assigned thisJun 10, 2022
@johnstcnjohnstcn requested a review fromammarioJune 10, 2022 18:08
Comment on lines 24 to 54
func TimezoneIANA() (*time.Location, error) {
if tzEnv, found := os.LookupEnv("TZ"); found {
if tzEnv == "" {
return time.UTC, nil
}
loc, err := time.LoadLocation(tzEnv)
if err != nil {
return nil, xerrors.Errorf("load location from TZ env: %w", err)
}
return loc, nil
}

lp, err := filepath.EvalSymlinks(etcLocaltime)
if err != nil {
return nil, xerrors.Errorf("read location of %s: %w", etcLocaltime, err)
}

// On Darwin, /var/db/timezone/zoneinfo is also a symlink
realZoneInfoPath, err := filepath.EvalSymlinks(zoneInfoPath)
if err != nil {
return nil, xerrors.Errorf("read location of %s: %w", zoneInfoPath, err)
}

stripped := strings.Replace(lp, realZoneInfoPath, "", -1)
stripped = strings.TrimPrefix(stripped, string(filepath.Separator))
loc, err := time.LoadLocation(stripped)
if err != nil {
return nil, xerrors.Errorf("invalid location %q guessed from %s: %w", stripped, lp, err)
}
return loc, nil
}
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Review: at a glance, the Darwin and Linux versions of these functions seems identical. Be assured they are not.

Comment on lines 26 to 71
func TimezoneIANA() (*time.Location, error) {
if tzEnv, found := os.LookupEnv("TZ"); found {
if tzEnv == "" {
return time.UTC, nil
}
loc, err := time.LoadLocation(tzEnv)
if err != nil {
return nil, xerrors.Errorf("load location from TZ env: %w", err)
}
return loc, nil
}

// https://superuser.com/a/1584968
cmd := exec.Command("powershell.exe", "-NoLogo", "-NoProfile", "-NonInteractive")
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, xerrors.Errorf("run powershell: %w", err)
}

done := make(chan struct{})
go func() {
defer stdin.Close()
defer close(done)
_, _ = fmt.Fprintln(stdin, cmdTimezone)
}()

<-done

outBytes, err := cmd.CombinedOutput()
if err != nil {
return nil, xerrors.Errorf("execute powershell command %q: %w", cmdTimezone, err)
}

outLines := strings.Split(string(outBytes), "\n")
if len(outLines) < 2 {
return nil, xerrors.Errorf("unexpected output from powershell command %q: %q", cmdTimezone, outLines)
}
// What we want is the second line of output
locStr := strings.TrimSpace(outLines[1])
loc, err := time.LoadLocation(locStr)
if err != nil {
return nil, xerrors.Errorf("invalid location %q from powershell: %w", locStr, err)
}

return loc, nil
}
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Review: just don't stare too closely at this

@@ -74,7 +75,8 @@ func Weekly(raw string) (*Schedule, error) {
}

// Schedule represents a cron schedule.
// It's essentially a thin wrapper for robfig/cron/v3 that implements Stringer.
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Review: This wrapper is no longer thin.

Comment on lines +143 to +161
func (s Schedule) DaysOfWeek() string {
dow := strings.Fields(s.cronStr)[4]
if dow == "*" {
return "daily"
}
for _, weekday := range []time.Weekday{
time.Sunday,
time.Monday,
time.Tuesday,
time.Wednesday,
time.Thursday,
time.Friday,
time.Saturday,
} {
dow = strings.Replace(dow, fmt.Sprintf("%d", weekday), weekday.String()[:3], 1)
}
return dow
}

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Review: For display purposes, this just replaces the day-of-week numbers with their abbreviated equivalents.

testCase := testCase
//nolint:paralleltest // t.Setenv
t.Run(testCase.name, func(t *testing.T) {
t.Setenv("TZ", testCase.tzEnv)
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Review: Doingsetenv here to validate that the timezone specified in the schedule is used

Comment on lines +80 to +84
{
name: "TimezoneProvidedInsteadOfLocation",
input: []string{"09:00AM", "Sun-Sat", "CST"},
expectedError: errUnsupportedTimezone.Error(),
},
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

@Emyrk this one just for you :-)

Emyrk reacted with heart emoji
Copy link
Member

@mafredrimafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

A few suggestions and questions, but in general looks good! 👍🏻

Default: * (every day)
* Location (optional) must be a valid location in the IANA timezone database.
If omitted, we will fall back to either the TZ environment variable or /etc/localtime.
You can check your corresponding location by visiting https://ipinfo.io - it shows in the demo widget on the right.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This help is ❤️.

johnstcn reacted with heart emoji
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Yes, this is excellent.

_, _ = fmt.Fprintf(cmd.OutOrStdout(),
"%s will automatically start at %s %s (%s)\n",
workspace.Name,
schedNext.In(sched.Location()).Format(time.Kitchen),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Do we always want to show am/pm here, even if 24h was used to define it? Or perhaps vary depending on defaults for the users system or selected location? Or perhaps we should have a user preference down the line?

johnstcn reacted with thumbs up emoji
Copy link
MemberAuthor

@johnstcnjohnstcnJun 13, 2022
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This sounds like an internationalization problem to me, which I'm going to place inside a tin can and kick down the road for later. 😅

But yes, yes we should.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think preference is very location-dependent. It would be unfortunate to add more state for am/pm.


var errInvalidScheduleFormat = xerrors.New("Schedule must be in the format Mon-Fri 09:00AM America/Chicago")
var errInvalidTimeFormat = xerrors.New("Start time must be in the format hh:mm[am|pm] or HH:MM")
var errUnsupportedTimezone = xerrors.New("The location you provided looks like a timezone. Check https://ipinfo.io for your location.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Nit: Go Errors should be lower case.

But technically these are help/documentation, so I understand the use of proper sentence structure.

(This isnon-blocking as I think the right approach might require some more think-through, but writing down my thoughts.)

I have one suggestion, that could have some benefits down the line if we e.g. want to translate the CLI, etc:

funcFormatCliError(errerror)string {switcherr {caseerrInvalidScheduleFormat:return"Schedule ..."// ...}}

We could optionally have a separatetype cliError struct{} type which we print in this special way.

Or perhaps rather we could have:

typecliErrorstruct{errstringcode clierror.Code}funcnewCliError(code clierror.Code,estring)errorvarerrInvalidScheduleFormat=newCliError(clierror.InvalidSchedule,"invalid schedule format")

Where we could keep an enum of cli error messages in e.g. a separate package. Just ideas of the top of my head.

We could also do something simpler like uppercasing the first letter of the error when we print it. I think it'd be helpful if error messages looked consistent across the CLI.

johnstcn reacted with thumbs up emoji
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We have something very similar inside another codebase which shall not be named ;-)
But yes, this needs more noodling.

if assert.NotEmpty(t, actualSchedule) {
assert.Equal(t, testCase.expectedSchedule, actualSchedule.String())
}
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

These are some beautiful tests! ❤️

johnstcn reacted with heart emoji
Default: * (every day)
* Location (optional) must be a valid location in the IANA timezone database.
If omitted, we will fall back to either the TZ environment variable or /etc/localtime.
You can check your corresponding location by visiting https://ipinfo.io - it shows in the demo widget on the right.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Yes, this is excellent.

_, _ = fmt.Fprintf(cmd.OutOrStdout(),
"%s will automatically start at %s %s (%s)\n",
workspace.Name,
schedNext.In(sched.Location()).Format(time.Kitchen),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think preference is very location-dependent. It would be unfortunate to add more state for am/pm.

@johnstcnjohnstcnenabled auto-merge (squash)June 13, 2022 20:44
@johnstcnjohnstcndisabled auto-mergeJune 13, 2022 21:00
@johnstcnjohnstcn merged commit0a949aa intomainJun 13, 2022
@johnstcnjohnstcn deleted the cj/1647/autostart-set-unset branchJune 13, 2022 21:09
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@mafredrimafredrimafredri approved these changes

@ammarioammarioammario approved these changes

Assignees

@johnstcnjohnstcn

Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

Streamlinecoder autostart UX
3 participants
@johnstcn@mafredri@ammario

[8]ページ先頭

©2009-2025 Movatter.jp