<commit_before>
import {Watcher} from "./watcher";
import * as actions from "../actions";

import * as os from "../os";
import sf from "../os/sf";
import * as ospath from "path";

import rootLogger from "../logger";
const logger = rootLogger.child({name: "open-at-login"});

import {createSelector} from "reselect";

import {IStore, IPreferencesState} from "../types";

async function updateOpenAtLoginState(store: IStore, openAtLogin: boolean, openAsHidden: boolean) {
  logger.debug(`Updating login item settings, open=${openAtLogin}, hidden=${openAsHidden}`);

  const app = require("electron").app;

  if (os.platform() === "linux") {
    // cf. https://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html#startup
    const configHome = process.env.XDG_CONFIG_HOME || ospath.join(app.getPath("home"), ".config", "autostart");
    const desktopFileName = `io.itch.${app.getName()}.desktop`;
    const desktopFilePath = ospath.join("/usr/share/applications", desktopFileName);
    const autostartFilePath = ospath.join(configHome, desktopFileName);

    logger.info(`Copying ${desktopFilePath} => ${autostartFilePath}`);

    if (openAtLogin) {
      try {
        if (!(await sf.exists(desktopFilePath))) {
          store.dispatch(actions.openAtLoginError({cause: "no_desktop_file"}));
          return;
        }

        if (!(await sf.exists(configHome))) {
          await sf.mkdir(configHome);
        }

        const desktopContents = await sf.readFile(desktopFilePath, {encoding: "utf8"});
        if (await sf.exists(autostartFilePath)) {
          await sf.unlink(autostartFilePath);
        }

        await sf.writeFile(autostartFilePath, desktopContents, {encoding: "utf8"});
      } catch (err) {
        logger.error(`Error while symlinking ${autostartFilePath}: ${err.message}`);
        store.dispatch(actions.openAtLoginError({cause: "error", message: err.message}));
        return;
      }
    } else {
      try {
        await sf.unlink(autostartFilePath);
      } catch (err) {
        logger.error(`Error while unlinking ${autostartFilePath}: ${err.message}`);
      }

      store.dispatch(actions.openAtLoginError(null));
    }
  } else {
    // macOS, Windows
    app.setLoginItemSettings({
      openAtLogin: openAtLogin,
      openAsHidden: openAsHidden,
    });
  }
}

let cachedSelector: (prefs: IPreferencesState) => void;
function getSelector (store: IStore) {
  if (!cachedSelector) {
    cachedSelector = createSelector(
      (prefs: IPreferencesState) => prefs.openAtLogin,
      (prefs: IPreferencesState) => prefs.openAsHidden,
      (openAtLogin: boolean, openAsHidden: boolean) => {
        updateOpenAtLoginState(store, openAtLogin, openAsHidden);
      },
    );
  }

  return cachedSelector;
}

export default function (watcher: Watcher) {
  watcher.on(actions.updatePreferences, async (store, action) => {
    const selector = getSelector(store);
    selector(store.getState().preferences);
  });
};
<commit_msg>linux: Don't log error if enoent while trying to unlink autostartFilePath<commit_after>
import {Watcher} from "./watcher";
import * as actions from "../actions";

import * as os from "../os";
import sf from "../os/sf";
import * as ospath from "path";

import rootLogger from "../logger";
const logger = rootLogger.child({name: "open-at-login"});

import {createSelector} from "reselect";

import {IStore, IPreferencesState} from "../types";

async function updateOpenAtLoginState(store: IStore, openAtLogin: boolean, openAsHidden: boolean) {
  logger.debug(`Updating login item settings, open=${openAtLogin}, hidden=${openAsHidden}`);

  const app = require("electron").app;

  if (os.platform() === "linux") {
    // cf. https://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html#startup
    const configHome = process.env.XDG_CONFIG_HOME || ospath.join(app.getPath("home"), ".config", "autostart");
    const desktopFileName = `io.itch.${app.getName()}.desktop`;
    const desktopFilePath = ospath.join("/usr/share/applications", desktopFileName);
    const autostartFilePath = ospath.join(configHome, desktopFileName);

    logger.info(`Copying ${desktopFilePath} => ${autostartFilePath}`);

    if (openAtLogin) {
      try {
        if (!(await sf.exists(desktopFilePath))) {
          store.dispatch(actions.openAtLoginError({cause: "no_desktop_file"}));
          return;
        }

        if (!(await sf.exists(configHome))) {
          await sf.mkdir(configHome);
        }

        const desktopContents = await sf.readFile(desktopFilePath, {encoding: "utf8"});
        if (await sf.exists(autostartFilePath)) {
          await sf.unlink(autostartFilePath);
        }

        await sf.writeFile(autostartFilePath, desktopContents, {encoding: "utf8"});
      } catch (err) {
        logger.error(`Error while symlinking ${autostartFilePath}: ${err.message}`);
        store.dispatch(actions.openAtLoginError({cause: "error", message: err.message}));
        return;
      }
    } else {
      try {
        await sf.unlink(autostartFilePath);
      } catch (err) {
        if (err.code === "ENOENT") {
          // not even there, good!
        } else {
          logger.error(`Error while unlinking ${autostartFilePath}: ${err.message}`);
          return;
        }
      }

      store.dispatch(actions.openAtLoginError(null));
    }
  } else {
    // macOS, Windows
    app.setLoginItemSettings({
      openAtLogin: openAtLogin,
      openAsHidden: openAsHidden,
    });
  }
}

let cachedSelector: (prefs: IPreferencesState) => void;
function getSelector (store: IStore) {
  if (!cachedSelector) {
    cachedSelector = createSelector(
      (prefs: IPreferencesState) => prefs.openAtLogin,
      (prefs: IPreferencesState) => prefs.openAsHidden,
      (openAtLogin: boolean, openAsHidden: boolean) => {
        updateOpenAtLoginState(store, openAtLogin, openAsHidden);
      },
    );
  }

  return cachedSelector;
}

export default function (watcher: Watcher) {
  watcher.on(actions.updatePreferences, async (store, action) => {
    const selector = getSelector(store);
    selector(store.getState().preferences);
  });
};

{'fraction_non_alphanumeric': 0.14332300668514594, 'fraction_numerical': 0.0006522093592043046, 'mean_word_length': 3.4352856109906003, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4486624', 'n_tokens_mistral': 1860, 'n_tokens_neox': 1832, 'n_words': 391}